标签:本地 min 总结 收集器 major gc 堆内存 enc 做了 需要
初级 Java 程序员步入中级程序员的有一个无法绕过的阶段------GC(Garbage Collection)。作为 Java 程序员,说实话,很幸福,不用像 C 程序员那样,时刻关心着内存,就像网上有句名言------生活从来都不容易,只不过是有人替你负重前行!是的,GC 在替我们做这些脏活累活,GC 像让我们把精力都放在业务上,而不用每时每刻都在想着内存。现在,GC 也是每个语言的标准配置了。不然谁会去使用这个语言呢?
然而,作为一个合格的程序员,对底层的好奇是进步的动力,如果一个程序员失去了好奇心,那就可以说他在程序员这条道路上就结束了。
难道我们不好奇 GC 到底是怎么做的吗?接下来,我们就分析 GC 做了哪些事情。
实际上,GC 主要做3件事情:
说到底,GC 就是做这3件事情,如果你能解决这3个问题,那么你也可以实现一个 GC。
那我们就一个一个问题来看看。
还记得我们之前分享的关于 JVM 运行时数据区吗?有堆,有栈,有方法区(永久代),还有直接内存,还有 PC 寄存器。其中,GC 的主要战场就是堆,当然,方法区也是需要 GC 的。但重点还是堆。
我们知道,堆中内存是共享的,基本所有的对象都是在堆中创建。当一个对象不需要使用了,理论上我们就需要释放他所占用的内存。
问题来了,如何分辨一个对象不需要使用了呢?答案是:不可能被任何途径使用的对象。也就是说他没有了任何引用。我们知道,引用在栈中,实例在堆中,当一个实例没有了指向他的引用,我们认为,这个实例就需要清除并释放他所占用的内存了。
那么 GC 是如何实现的呢?一般而言有2种方法:
什么是引用计数法呢?
给对象中添加一个引用计数器,每当有一个地方引用他是,计数器值就加1;当引用失效时,计数器值就减1;任何时刻计数器为0的对象就是不可能在被使用的。
虽然乍看这个算法简单,效率也高,但有一个问题这个算法无法解决,就是循环引用。试想一下:A 对象引用了 B,B 对象也引用了 A,但 A 和 B 都不被别的地方使用,也就是说,实际上这两个对象是垃圾对象,但是由于他们互相持有引用,导致他们的引用计数器都不为0,因此系统无法判断是垃圾,也无法回收他们。
所以,在现在的 JVM 中,是没有使用这个算法的。我们知道就行。
引用计数法不行,那就再说说可达性分析算法。
这个算法的基本思想就是通过一系列的称为 “GC Roots” 的对象作为起始点,从这些节点开始向下搜索,所有所走过的路径称为引用链(Reference Chain),当一个对象到 GC Roots 没有任何引用链相连(也就是对象不可达)时,则证明此对象是不可用的。如下图所示,obj5 , obj6, obj7 虽然互相有关联,但是他们到 GC Roots 是不可达的,所以他们将会判定为是可回收的对象。
那么哪些对象可以作为 GC Roots 对象呢?
注意:即使是在可达性分析算法中不可达的对象,也并非是"非死不可的",这时候他们实际上是处于 “缓刑” 阶段。因为要真正宣告一个对象的死亡,至少需要经历两次标记过程:
finalize 方法是对象逃脱死亡命运的最后一道关卡。稍后 GC 将对队列中的对象进行第二次规模的标记,如果对象要在 finalize 中 “拯救” 自己,只需要将自己关联到引用上即可,通常是 this。如果这个对象关联上了引用,那么在第二次标记的时候他将被移除出 “即将回收” 的集合;如果对象这时候还没有逃脱,那基本上就是真的被回收了。
这里需要注意的一点就是:一个对象如果重写了 finalize 方法,那么这个方法最多只会被执行一次。
建议:如非必要,不要重写该方法。可以使用 try-finally 代替,此方式更好,更及时。同时注意:在 Mysql 的 JDBC 驱动中,com.mysql.jdbc.ConnectionImpl 就实现了 finalize 方法,作用是:当一个 JDBC Connection 被回收时,需要进行连接的关闭,如果开发人员忘记了关闭,则在 finalize 方法中进行关闭。但是,由于其调用的不确定性,这不能单独作为可靠的资源回收手段。
到这里,我们知道了什么时候进行回收:如果一个对象重写了 finalize 方法且这个方法没有被 JVM 调用过,那么这个对象会被放入一个队列等待被一个低优先级的线程执行 finalize 方法,如果在这个方法中对象不能自救,则这个对象在第二次标记过程中就会被标记死亡,等待 GC 回收。
如何回收,这个问题非常的大,涉及到各种垃圾回收算法,各种垃圾收集器。限于本篇的篇幅,楼主将不会在这篇文章里深入探讨,这里只会列出一些大纲,这些大纲将是后面文章的摘要,我们将在后面的文章中深入探讨如何回收。
那么,有哪些摘要呢?
这些算法是 GC 的基础,所有 GC 的实现都是基于这些算法来清除无用对象,然后释放内存空间。我们将会在后面的文章一个一个讲解。
好,以上就是如何回收的大纲,我们将在后面的文章中慢慢讲解。
这篇文章主要总结了什么是 GC ,以及 GC 的作用,GC 主要做了3件事情,哪些内存需要回收,什么时候回收,如何回收。我们知道了 GC 通过可达性分析知道了哪些内存需要回收,那什么时候回收呢?执行 finalize 方法后如果还没有复活,将被回收。第三个问题:如何回收呢?这个问题是一个大课题,我们只是列出了一些大纲,比如有哪些垃圾收集器,有哪些垃圾算法,有哪些 GC 过程。这些细节我们将在后面慢慢讲解,逐步深入。
标签:本地 min 总结 收集器 major gc 堆内存 enc 做了 需要
原文地址:https://www.cnblogs.com/stateis0/p/9062182.html