Java垃圾回收算法是JVM的必备内容,也是Java面试经常考察的内容,下面我就重点详解4种Java垃圾回收算法@mikechen
1.标记清除算法
标记-清除算法将垃圾回收分为两个阶段:标记阶段和清除阶段。
如下图所示:
1.标记阶段
从程序的根对象开始,递归遍历所有可以到达的对象,并将它们标记为“可达”的对象。
根对象可以是全局变量、程序的调用栈、寄存器等,在遍历的过程中,将访问到的对象打上标记。
2.清除阶段
遍历整个堆,将没有标记的对象,即未被标记为“可达”,视为垃圾并回收其占用的内存。
然后,在清除阶段,清除所有未被标记的对象。
标记清除算法优点:
最基础简单的垃圾收集算法,为后续垃圾收集算法奠定了基础,实现起来比较简单。
标记清除算法缺点:
- 内存碎片:标记清除算法回收的内存是不连续的,可能会导致内存碎片问题,进而降低内存使用效率;
- 垃圾回收效率不高:标记清除算法需要对整个堆进行遍历,因此在堆比较大的情况下,垃圾回收效率较低;
- 扫描了整个空间两次:第一次:标记存活对象,第二次:清除没有标记的对象;
标记清除算法适用
标记清除算法适用于:存活对象较多的情况,比较适用于年老代。
2.复制算法
复制算法,如下图所示:
复制算法步骤,主要分为如下步骤:
第一步:标记出所有的存活对象
从根集合节点进行扫描,例如:线程栈中的对象、静态变量、寄存器中的指针等,标记出所有的存活对象,
第二步:复制对象到新内存
找出所有仍然存活的对象,并将这些存活的对象复制到一块儿新的内存,比如:上方图片下边的那一块儿绿色内存。
第三步:回收垃圾并被清除
当所有存活的对象都被复制到To区后,From区中的所有对象都可以被清除(图中上边的那一块儿内存)。
复制算法优点:
复制算法的优点是实现简单,只需要将存活对象复制到新的内存区域中即可,非常高效。
复制算法缺点:
需要更多的内存空间,因为JVM复制算法需要将存活对象复制到新的内存区域中,所以需要两倍的内存空间,这可能会导致内存空间的浪费。
复制算法适合
复制算法适合存活对象较少的情况下比较高效,基本上98%的对象是”朝生夕死”的,存活下来的会很少,所以特别适合于新生代。
3.标记整理算法
复制算法的高效性是建立在存活对象少的前提下,这种情况在新生代经常发生,但是在老年代更常见的情况是大部分对象都是存活对象。
如果依然使用复制算法,由于存活的对象较多,复制的成本也将很高,所以后面就出来了标记整理算法。
如下图所示:
标记整理算法步骤,主要分为如下4个步骤:
- 遍历内存中的所有对象,标记出所有正在使用的对象。
- 将所有标记过的对象移动到内存的一端,形成一个连续的内存块,同时将这些对象的地址更新到新的位置上。
- 将内存块另一端的所有未标记对象删除,并将这些内存空间标记为可用。
- 更新所有指向移动对象的指针,使其指向新的地址。
标记整理算法适合
标记整理算法适合老年代进行垃圾收集,parallel Oldgc和Serial old收集器就是采用该算法进行回收的。
4.分代收集算法
分代收集算法就是目前虚拟机使用的回收算法,这种算法根据对象的存活周期的不同将内存划分成几块,新生代和老年代,这样就可以根据各个年代的特点采用最适当的收集算法。
在JVM中,堆内存被分为三个部分:年轻代、老年代和永久代(在Java 8中,永久代被元空间所替代)。
JVM分代算法可以有效地提高垃圾回收的效率,因为不同代中对象的存活时间和存活概率不同,采用不同的垃圾回收策略可以使得垃圾回收的效率更高。
每一种JVM垃圾回收算法都会有很多不同的垃圾回收器去实现,在实际使用中,根据自己的业务特点做出选择就好。
陈睿mikechen
10年+大厂架构经验,资深技术专家,就职于阿里巴巴、淘宝、百度等一线互联网大厂。
关注「mikechen」公众号,获取更多技术干货!
后台回复【面试】即可获取《史上最全阿里Java面试题总结》,后台回复【架构】,即可获取《阿里架构师进阶专题全部合集》