JVM垃圾回收算法的优缺点

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/s3395719/article/details/80640455
最近在学习JVM的一些知识,所以特意写下学习笔记来简单记录知识点,由于只是初步的学习,下面本人所总结的内容都比较简单且不一定正确,如果有什么错误希望大家能指出来,我看到后会进行修正。

垃圾分析算法

功能:分析JVM堆上哪些对象是“垃圾”

引用计数法
每一个对象都有一个引用计数器,当被引用一次时,它都会 +1,引用取消时 -1,当执行GC时,所有引用计数器为 0 的对象都会被视为“垃圾”。
优点:相对于其他垃圾回收算法,标记清除法实现相对简单。
缺点:当两个对象相互引用时,就会无法被清除;。

可达性分析算法(主流)
以方法区的静态变量或栈针变量表的变量为Root根节点,通过这个root去找其他下级节点,无法到达的对象在GC中会被清理。

垃圾收集算法

标记清除算法
把所有需要回收的对象作一个标记,GC回收的时候会把所有被标记的对象回收。
优点:简单
缺点:垃圾回收后内存会变得不连续,造成很大零散的内存区域。以后新创建的大对象可能会不够空间存储。

复制算法(大多JVM的GC都使用这个)
通俗点说,把原本存放对象的一块大区域拆分为 1个Eden和2个Survivor,创建新对象时仅使用其中一块区域Eden,当Eden满了后触发minorGC,清空Eden和其中一个Survivor1前把幸存的对象复制到Survivor2,然后再清空Eden和Survivor1(仅概念上简述,实际情况很复杂,请看其他文章详细分析)
优点:GC后的内存空间是连续的。
缺点:由于分出了Survivor2不存放对象,真正存放新对象的内存区域会变少,Eden:Survivor1:Survivor2比例为8:1:1,少了10%的可用内存。

标记-整理法
类似与标记清除法一样,第一步先把需要回收的对象标记,不同的是第二步把活动的对象(幸存)往内存一边移动。堆内存就像一列队伍,把所有要留下的对象都往前靠,后面剩下的都是即将回收的对象(垃圾)。
优点:避免了“标记清除法”和“复制算法”的缺点。
缺点:效率比较低。

分代收集法

书中把这个算法和垃圾收集算法放在了一起,但我觉得分代收集与上面的“垃圾收集算法”有一点本质区别。前者是GC的设计方式,后者是GC回收的具体思路。

堆内存被分为 新生代和老年代,其中 新生代一般分为eden和Survivor(上文简述过)。在新生代的gc成为 minorGC,老年代的称为majorGC/fullGC,新创建的对象属于新生代,在经历了N次minorGC后(N可调大小,默认15),会转到老年代。
新生代的区域和老年代区域比例一般为1:2。两个区域的垃圾收集算法都可以不同,新生代一般为“复制算法”,老年代为“标记-整理法”。

为什么新生代使用“复制算法”,老年代使用“标记-整理法”?
因为在Java程序中,大部分对象都是“朝生夕死”,很快会被回收的,所以新生代的minorGC的触发频率要远大于老年代的majorGC,这就需要效率更高的“复制算法”,而老年代由于majorGC触发频率比较低,所以可以选择效率较低的“标记整理法”来节约内存。
此外,值得一提的是新生代的eden内存要大于Survivor内存,这样就会出现一个问题:当eden中有一部分对象生命周期一样并且占用的内存大于Survivors时,执行minorGC仍然幸存,Survivor将无法存放这么多的对象。这时老年代就会起到“担保”作用,那些存活的对象将直接晋升到老年代。同理“复制算法”需要有人来做担保,这也是老年代使用“标记整理法”的原因之一。

猜你喜欢

转载自blog.csdn.net/s3395719/article/details/80640455
今日推荐