JVM深入理解(一)

1.垃圾判断算法

判断JVM中的所有对象,哪些对象是存活的,哪些对象可回收的算法。

引用计数算法

在这里插入图片描述
最简单的垃圾判断算法。
在对象中添加一个属性用于标记对象被引用的次数,每多一个其他对象引用,计数+1,当引用失效时,计数-1,如果计数=0,表示没有其他对象引用,就可以被回收,但无法解决循环依赖的问题。

可达性分析算法
在这里插入图片描述
以GC Roots对象作为起点,从根节点向下搜索,走过的路径称为引用链,当一个对象到GC Roots没有引用链相连时,则说明该对象无引用执行,可回收,相反,则对象处于存活状态,不可回收。

哪些对象可以作为GC Root呢

线程栈的本地变量、静态变量、本地方法栈的变量等等

2.垃圾回收算法

标记-清除算法
算法分为“标记”和“清除”阶段:⾸先标记出所有需要回收的对象,在标记完成后统⼀回收所有被标记的对象。它是最基础的收集算法,后续的算法都是对其不⾜进⾏改进得到。
在这里插入图片描述

复制算法
将内存分为⼤⼩相同的两块,每次使⽤其中的⼀ 块。当这⼀块的内存使⽤完后,就将还存活的对象复制到另⼀块去,然后再把使⽤的空间⼀次清理掉, 这样就使每次的内存回收都是对内存区间的⼀半进⾏回收。
在这里插入图片描述

标记-整理算法
标记过程仍然与“标记-清除”算法⼀样,但后续步骤不是直接对可回收对象回收,而是让所有存活的对象向⼀端移动,然后直接清理掉端边界以外的内存。
在这里插入图片描述
分代收集算法
根据对象存活周期的不同将内存分为几块。⼀般将java堆分为新⽣代和老年代,这样就可以根据各个年代的特点选择合适的垃圾收集算法。比如在新⽣代中,每次收集都会有⼤量对象死去,所以可以选择复制算法,只需要付出少量对象的复制成本就可以完成每次垃圾收集。而老年代的对象存活⼏率是比较⾼的,而且没有额外的空间对它进⾏分配担保,所以我们必须选择“标记-清除”或“标记-整理”算法进⾏垃圾收集。

3.JVM内存分配策略

对象优先分配在 Eden
首先尝试在 Eden 分配,若 Eden 空间不足,就发起 YoungGC(简称YGC)

Eden与Survivor区默认8:1:1
大量的对象被分配在eden区,eden区满了后会触发minor gc,可能会有99%以上的对象成为垃圾被回收掉,剩余存活的对象会被挪到为空的那块survivor区,下一次eden区满了后又会触发minor gc,把eden区和survivor区垃圾对象回收,把剩余存活的对象一次性挪动到另外一块为空的survivor区,因为新生代的对象存活时间很短,所以JVM默认的8:1:1的比例是很合适的,让eden区尽量的大,survivor区够用即可
大对象直接进入老年代
大对象就是需要大量连续内存空间的对象(比如:字符串、数组)。JVM参数 -XX:PretenureSizeThreshold 可以设置大对象的大小,如果对象超过设置大小会直接进入老年代,不会进入年轻代,这个参数只在 Serial 和ParNew两个收集器下有效,可以避免为大对象分配内存时的复制操作而降低效率。
长期存活的对象将进入老年代
虚拟机给每个对象设置一个对象年龄(Age)计数器。
如果对象在 Eden 出生并经过第一次 Minor GC 后仍然能够存活,并且能被 Survivor 容纳的话,将被移动到 Survivor 空间中,并将对象年龄设为1。对象在 Survivor 中每熬过一次 MinorGC,年龄就增加1岁,当它的年龄增加到一定程度(默认为15岁),就会被晋升到老年代中。对象晋升到老年代的年龄阈值,可以通过参数 -XX:MaxTenuringThreshold 来设置。
对象动态年龄判断
当前放对象的Survivor区域里(其中一块区域,放对象的那块s区),一批对象的总大小大于这块Survivor区域内存大小的50%,那么此时大于等于这批对象年龄最大值的对象,就可以直接进入老年代了,例如Survivor区域里现在有一批对象,年龄1+年龄2+年龄n的多个年龄对象总和超过了Survivor区域的50%,此时就会把年龄n(含)以上的对象都放入老年代。这个规则其实是希望那些可能是长期存活的对象,尽早进入老年代,对象动态年龄判断机制一般是在minor gc之后触发的。

优化思路:
尽量让每次Young GC后的存活对象小于Survivor区域的50%,都留存在年轻代里,尽量别让对象进入老年代,尽量减少Full GC的频率,避免频繁Full GC对JVM性能的影响。

4.OOM与调优

最常见的OOM情况有以下三种

java.lang.OutOfMemoryError: Java heap space ------>java堆内存溢出,此种情况最常见,一般由于内存泄露或者堆的大小设置不当引起。对于内存泄露,需要通过内存监控软件查找程序中的泄露代码,而堆大小可以通过虚拟机参数-Xms,-Xmx等修改。
java.lang.OutOfMemoryError: PermGen space ------>java永久代溢出,即方法区溢出了,一般出现于大量Class或者jsp页面,因为上述情况会产生大量的Class信息存储于方法区。此种情况可以通过更改方法区的大小来解决,(-XX:PermSize=64mXX:MaxPermSize=256m)的形式修改,过多的常量尤其是字符串也会导致方法区溢出。
java.lang.StackOverflowError ------> 不会抛OOM error,但也是比较常见的Java内存溢出。JAVA虚拟机栈溢出,一般是由于程序中存在死循环或者深度递归调用造成的,栈大小设置太小也会出现此种溢出。可以通过虚拟机参数-Xss来设置栈的大小。

Arthas调优工具

启动 authas

curl -O https://arthas.aliyun.com/arthas-boot.jar
java -jar arthas-boot.jar

选择应用java进程:
在这里插入图片描述
3. 查看dashboard
输入dashboard,会展示当前进程的信息,按ctrl+c可以中断执行
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值