「这是我参与11月更文挑战的第14天,活动详情查看:2021最后一次更文挑战」
接 JVM(五)--垃圾回收机制(一),我们这次研究垃圾回收算法
一、 标记方法
JVM没有采用引用计数器。引用计数器有个坑,不能处理相互引用,JVM采用的可达性分析。所以我们就不研究引用计数器这种算法了
可达性分析
这个算法的思想是通过“GC Roots”对象作为起点,从这些节点向下搜索,如果一个对象到“GC Roots”没有任何引用链,则证明此对象是不可用的 根搜索算法中不可达的对象并非“非死不可”,这时候它们暂时处于“缓刑”阶段,真正宣告一个对象死亡,至少要经历两次标记过程。
可以作为“GC Roots”的对象有:
- 虚拟机栈中引用的对象(栈帧中的本地变量表)
- 方法区中的常量引用的对象。
- 方法区中类静态属性引用的对象。
- 本地方法栈中JNI(Native方法)的引用对象。
- 活跃线程的引用对象
二、 回收算法
- 标记-清除算法
- 复制算法
- 标记-整理算法
- 分代收集算法
1. 标记-清除算法
先找到内存里的存活对象并对其进行标记,然后统一把未标记的对象统一的清理
缺点:标记和清除效率不高,清除后会产生大量不连续的碎片
2. 复制算法
它将可用内存按容量划分为大小相等的两块,每次使用其中的一块。当这块的内存用完了,就将还存活着的对象复制到另一块上面,然后再把已使用过的内存空间一次清理掉
优点:每次都是对其中的一块进行内存回收,内存分配时就不用考虑内存碎片等复杂情况,只要移动堆顶指针,按顺序分配内存即可,实现简单,运行高效。
缺点:是将内存缩小为原来的一半,代价太高了一点。
3. 标记-整理算法
让所有存活的对象都向一端移动,然后直接清理掉端边界以外的内存
- 标记阶段
- 整理阶段:移动存活对象,同时更新存活对象中所有指向被移动对象的指针 优点:解决了标记清除法的空间碎片问题,同时也不至于像标记复制法需要空闲的内存空间
缺点:记整理法是三种垃圾回收算法中性能最低的一种,因为标记整理法在移动对象的时候不仅需要移动对象,还要额外的维护对象的引用的地址,这个过程可能要对内存经过几次的扫描定位才能完成
4. 分代收集算法
根据对象的存活周期的不同将内存划分为几块,一般是把Java堆分为新生代和老年代,这样就可以根据各个年代的特点采用最适当的收集算法。在新生代中,每次垃圾收集时都发现有大批对象死去,只有少量存活,那就选用复制算法,只需要付出少量存活对象的复制成本就可以完成收集。而老年代中因为对象存活率高、没有额外空间对它进行分配担保,就必须使用“标记-清理”或“标记-整理”算法来进行回收。