14.垃圾回收相关算法
一、标记阶段:引用计数算法
1.1 垃圾标记阶段:垃圾存活判断
答:只有被标记为已经死亡的对象(没有任何指针指向它),GC才会在执行垃圾回收时,释放掉其所占的空间,因此这个过程叫做 垃圾标记阶段
两种方式:引用计数算法和可达性分析算法
1.2 引用计数算法:记录对象被引用的情况,被引用就+1,引用失效就-1,值为0时候,可以被回收
优点:实现简单,便于辨别;判断效率高,回收没有延迟性
缺点:
1.需要单独的字段存储计数器,增加了存储空间的开销
2.每次赋值都要更新计数器,增加时间的开销
3.无法处理循环引用的场景,致命缺点,导致java的回收器没有使用本类算法

...

二、标记阶段:可达性分析是算法(根搜索算法、追踪性垃圾收集)
相对于引用计数算法而言,可达性分析算法不仅同样具备实现简单和执行高效等特点,更重要的是该算法可以有效地解决在引用计数算法中循环引用的问题,防止内存泄漏的发生。
基本思路:图解

基本思路:

2.1、GC Roots可以是哪些具体元素?
小技巧:
由于GC Roots采用的是栈方式存储变量和指针,所以,如果一个指针,它保存了堆内存里面的对象,但是它自己又不在堆内存里面,那么它就是一个Roots

三、对象的finalization机制
可以重写finalize()方法,但是不建议自己主动调用,因为垃圾回收器会自动调用
不发生GC,则不执行finalize()方法。
finalize()和C++的析构函数 很类似。
java对象的三种状态:可触及,可复活,不可触及

---------

四、MAT与Jprofiler的GC Roots溯源

五、清除阶段:标记-清除算法(Mark-Sweep)
5.1、清除没被标记的对象
当成功区分出内存中存活对象和死亡对象后,GC接下来的任务就是执行垃圾回收,释放掉无用对象所占用的内存空间,以便有足够的可用内存空间为新对象分配内存。
5.2、执行过程:
当堆中的有效内存空间(available memory)被耗尽的时候,就会停止整个程序(也被称为stop the world)I,然后进行两项工作,第一项则是标记,第二项则是清除。
1.标记:collector从引用根节点开始遍历,标记所有被引用的对象。一般是在对象的Header中记录为可达对象。
2.清除:collector对堆内存从头到尾进行线性的遍历,如果发现某个对象在其Header中没有标记为可达对象,则将其回收。
5.3、缺点:
1.效率不高
2.在进行GC的时候,需要停止用户线程,导致用户体验差
3.这种方式清理出来的空间是不连续的,会产生内存碎片,需要维护一个空闲列表(空闲内存的地址)
5.4、何为清除?
**把需要清除的地址保存在 空闲列表里面,就说明这块地址空闲了(实际没删),下次有新对象加载时候,判断垃圾 的位置空间是否够,如果够,则覆盖。
**
图解:

六、清除阶段:复制算法(Copying)
为了解决上一个算法的缺陷
核心思想:
将活着的内存空间分为两块,每次只使用其中一块,在垃圾回收时将正在使用的内存中的存活对象复制到未被使用的内存块中,之后清除正在使用的内存块中的所有对象,交换两个内存的角色,最后完成垃圾回收。
优缺点
优点:
**1.没有标记和清除阶段,实现简单,运行高效
2.复制过程中可以保证地址的连续性,不出出现“碎片”的问题
**
缺点:
**1.需要两倍的内存空间
2.对于G1(垃圾回收器)这种拆成大量的region的GC,复制而不是移动,意味着GC需要维护region之间对象的引用关系,不管是内存占用或者时间开销都不小,需要修改指针地址表的。
**
特别的:
**如果系统中垃圾对象较多,复制算法不会很理想,因为:复制算法需要复制的存活对象并不会太大,或者说非常低才行
**
应用场景:
from区和 to 区 很理想

图解:
双向的 A<====>B

七、清除阶段:标记-压缩(整理)算法(Mark-compact)
背景
复制算法的高效性是建立在存活对象少、垃圾对象多的前提下的。这种情况在新生代经常发生,但是在老年代,更常见的情况是大部分对象都是存活对象。如果依然使用复制算法,由于存活对象较多,复制的成本也将很高。因此,基于老年代垃圾回收的特性,需要使用其他算法
标记清除算法和标记压缩算法区别
1>标记-压缩算法的最终效果等同于标记-清除算法执行完成后,再进行一次内存碎片整理,因此,也可以把它称为标记-清除-压缩(Mark-Sweep-Compact)算法。
2>二者的本质差异在于标记-清除算法是一种非移动式的回收算法,标记-压缩是移动式的。是否移动回收后的存活对象是一项优缺点并存的风险决策。
3>可以看到,标记的存活对象将会被整理,按照内存地址依次排列,而未被标记的内存会被清理掉。如此一来,当我们需要给新对象分配内存时,JVM只需要持有一个内存的起始地址即可,这比维护一个空闲列表显然少了许多开销。
优缺点
优点:
1>消除了标记-清除算法中,内存碎片的问题,我们需要重新分配内存时,JVM只需要持有一个内存的起始地址就可以了,使用指针碰撞
2>消除了复制算法当中,内存减半的代价
缺点:
1>标记压缩算法效率低于复制算法
2>移动对象的同时,如果对象被其他对象引用,则还需要调整引用的地址
3>移动过程当中,需要暂停用户线程,STW
图解

八、小结
Mark-Sweep Mark-Compact Copying
速度上: 中等 最慢 最快
空间开销: 少(有碎片) 少(有碎片) 需要两倍内存(不存在碎片)
移动对象: 否 是 是
九、分代收集算法
新生代:复制算法
老年代:标记-压缩算法或标记-清除的混合

十、增量收集算法、分区算法
为了降低延迟
增量收集算法:用户线程和垃圾收集交替之星
优缺点:
优点:减少了用户卡段的时间
缺点:因为线程间的切换,增大了垃圾回收的总体成本,造成系统吞吐量的下降
分区算法:


浙公网安备 33010602011771号