有位工作五年的小伙伴面试被问到JVM相关的问题,说请你谈谈你对JVM中主要GC算法的理解,我给大家分享一下我的理解。
1 主要垃圾回收算法
GC翻译过来叫做垃圾回收,那么JVM中主要的垃圾回收算法有三种,分别是:标记清除算法、标记复制算法和标记整理算法。
下面,我介绍一下每种算法的核心原理:
首先是,标记清除算法。它是将存活的对象打上标记,那么没有被标记的对象就是需要被回收的垃圾对象,这些垃圾对象会被垃圾回收器直接回收。
然后是,标记复制算法。它是把内存分为两等份,每次只使用其中的一份,等到正在使用的这部分内存满了之后,就会标记出存活的对象,然后把存活的对象拷贝到另一部分闲置的内存中,那留在另一部分内存中的对象,会全部被垃圾回收器回收。那么,原来空闲的内存空间就会变成使用中的状态,而原来使用中的内存空间会被闲置出来继续使用。这就是标记复制算法的一次完整的GC。然后,一直重复这个循环。
最后是,标记整理算法。它是先标记出存活的对象,然后,把所有存活的对象整理到内存空间的另一端,而没有被标记的对象就是可以被覆盖或者是释放。
2 优缺点分析
接下来,分析一下三种GC算法的优缺点。
首先来看,标记清除算法。它主要的缺点是会产生比较多的内存碎片,而这些内存碎片,随着系统运行时间的推移,系统运行时间长了以后,无法再大量分配连续的内存空间。这样的话,就会导致更加频繁地触发GC操作。
然后是,标记复制算法,它主要的缺点是,会导致我们实际使用的内存空间只有50%,而另外50%的内存空间是闲置的。所以,比较浪费内存空间。而且,如果大量复制对象的话,垃圾回收的耗时就比较长了,所以,这种算法,更加适合处理存活对象少,垃圾对象比较多的场景。
最后是,标记整理算法。它的本质和标记清除算法是基本差不多,只不过标记整理算法多了一个动作,会把存活的对象移动到一起。从垃圾收集和清理效率来看,增加了一个移动的动作,所以耗时会更久。但是,新分配对象的耗时就会下降。
3 分代回收
因为Java对象基本上都是临时的对象,很快就会被回收。所以,JVM的内存是分代的设计,根据对象在内存中的存活时间,分为年轻代、老年代和永久代。
那么年轻代呢,采用的是标记复制算法,在每次复制的时候,存活下来的对象会很少。
老年代呢,是经历过几次GC的对象,JVM会认为它可能继续存活下去,就不太适合采用标记复制算法,所以,老年代采用的是标记清除算法,比如CMS这种回收器就是采用标记清除的方式。
永久代呢,表示一直会存活的对象,只有在触发Full GC的时候才会被回收。所以,永久代对象创建过多的话,比较容易出现内存溢出。最典型的场景就是,在JSP页面比较多的情况,容易出现永久代内存溢出。
好了,以上就是我对垃圾回收算法的理解。
我是被编程耽误的文艺Tom,关注我,面试不再难!