当前位置: 首页 > 科技观察

面试的时候按照这个套路回答JavaGC相关的问题,你一定能过!

时间:2023-03-19 00:56:26 科技观察

大家好,我是鸭血粉。2020年注定是不平凡的一年。很多朋友在后台和星球上留言说今年好找工作难,也有应届生给阿芬留言问阿芬公司今年会不会招应届生,阿芬只能帮忙她的朋友问了HR,阿芬拿不定主意。就在前几天,有朋友在微信上问阿芬,说是去一家公司面试,被问到JavaGC相关的东西。尽管他通常是有准备的,但答案总是零散且不合逻辑。其实阿芬也能理解,现在面试都是一问一答的模式,一个是随便问,一个是死记硬背,很多时候面试前的准备工作都做好了,到了面试的时候,您可能会紧张而忘记它。这不好。本文将举例说明遇到问题或知识点时如何理解和学习。当JavaGC目标遇到一个问题或者一个知识点的时候,我们需要理解和理解我们要解决的是什么问题。说到JavaGC,这个GC的目的是什么?很明显,就是回收内存,因为内存是有限的。随着程序中创建的对象越来越多,如果进行回收,内存会越来越大,最后程序就会异常。既然目的是为了回收内存,那么一个新的问题就产生了,哪些对象可以被回收呢?什么时候回收?如何回收?Whichobjectscanbereclaimed简单的说就是可以回收无用的对象,那么换句话说,如果定义一个对象是无用的呢?这里主要有两种方法,一种叫引用计数法,一种叫可达性分析法。引用计数引用计数是指如果一个对象被另一个对象引用了一次,那么这个对象就会有一个引用计数器,这个计数器会加一;如果它被释放,引用计数器将减一。当引用计数器的计数为0时,表示该对象无用,此时可以回收这样的对象。表面上看似乎很有道理,实施起来也很方便,但是仔细想想就会发现问题出在哪里。循环引用的问题,比如对象A引用了对象B,但是对象B也引用了对象A,那么此时对象A和对象B的引用计数器的计数不会为0,但是两者都不会这两个对象被其他对象引用,理论上这两个对象都可以被回收。从上面可以看出,这个方案是有问题的,会导致内存泄漏。那么还有一个解决方案,就是可达性分析。可达性分析可达性分析是指从GCRoots点开始,向下查找。当没有找到引用链时,说明该对象是垃圾对象。那么哪些对象可以被认为是Roots节点呢?Java栈中有对象,方法区中有静态属性和常量,本地方法栈中有对象。从这几类对象依次往下查找。如果没有到达Roots节点的对象是垃圾对象,说明可以回收。如下图所示,对象A、B、C可以找到与Roots节点的连接,但是对象D、E、F找不到与Roots节点的连接,即不可达,所以三者对象DEF是垃圾对象。什么时候回收上面两种方案解决了哪些对象可以回收,那么接下来的问题就是什么时候进行垃圾回收了?当排除人为调用时,垃圾回收发生在为新对象分配内存时,此时如果内存空间不足,就会触发GC进行垃圾回收。如何回收上面我们知道了哪些对象是可以回收的,什么时候应该回收,那么接下来要解决的就是如何回收垃圾了。根据实现方式的不同,有许多不同的垃圾回收算法。例如,有标记清除算法、复制算法、标记排序算法和分代回收算法。下面简单介绍一下。如果你想了解更多,你可以自己研究。Mark-and-sweep算法mark-and-sweep算法很好理解。它主要执行两个动作,一个是标记,另一个是清除和回收标记的对象内存。该算法的一个问题是会出现严重的内存碎片。如下图:从上图可以看出,内存回收后出现了严重的内存碎片,导致在分配一些大对象时内存不足,但是整体内存确实是足够的。复制算法复制算法的实现比较简单明了。就是把内存霸道的分成两部分,平时使用的时候只用到其中的一部分。当需要进行GC时,将存活的对象复制到另一部分,然后清理所有使用过的内存。如下图所示:从上图可以看出标记清除的内存碎片问题已经解决了,但是很明显复制算法还有一个问题,就是内存使用率大大降低,可用内存只有原来的一半。标记算法既然标记清除算法和复制算法各有优缺点,我们自然会想到是否可以将这两种算法结合起来,于是出现了标记清除算法。标记阶段和mark-and-clear算法一样,先标记需要回收的部分,但是清除阶段不是直接清除,而是将存活的对象移动到内存的一端,然后清除休息。如下图所示:标记算法虽然可以解决上述两种算法的部分问题,但仍然需要先标记再移动,整体效率仍然较低。分代恢复算法分代恢复算法是目前应用广泛的一种算法。这不是什么新算法,只是划分内存而已。不同的内存区域使用不同的算法。根据对象的存活时间,内存分为新生代和老年代,其中新生代包括Eden区和S0、S1。复制算法用于新生代。分配对象内存时,只会使用Eden和S0区域。当GC发生时,存活的对象会被复制到S1区,然后循环复制。当一个对象在15次GC之后仍然存活时,该对象将进入老年代。老年代使用标记算法,因为每次回收的对象较少。垃圾收集器说完垃圾收集算法,我们再来看看垃圾收集器。每个垃圾收集器都是不同时代的不同产物,都有自己的独特性。串行垃圾收集器(单线程,复制算法)ParNew垃圾收集器(串行+多线程)并行Scavenge收集器(多线程复制算法,效率高)SerialOld收集器(单线程标记整理算法)ParallelOld收集器(多线程标记整理算法)CMS收集器(多-threadedmark-and-sweepalgorithm)G1collector各个垃圾收集器的用法可以参考下图。个人觉得没必要精通那么多收藏家。可以关注CMS和G1。向上。有兴趣的朋友可以自己研究。