本文共 5376 字,大约阅读时间需要 17 分钟。
引用实例被添加在引用队列中,可以在任何时候通过查询引用队列回收对象。
现在我对一个对象的生命周期进行描述:
package wys.demo1;public class Demo1 { public static Demo1 obj; @Override protected void finalize() throws Throwable { super.finalize(); System.out.println("CanReliveObj finalize called"); obj = this;// 把obj复活了!!! } @Override public String toString(){ return "I am CanReliveObj"; } public static void main(String[] args) throws InterruptedException{ obj = new Demo1();// 强引用 obj = null; //不会被立即回收,是可复活的对象 System.gc();// 主动建议JVM做一次GC,GC之前会调用finalize方法,而我在里面把obj复活了!!! Thread.sleep(1000); if(obj == null){ System.out.println("obj 是 null"); }else{ System.out.println("obj 可用"); } System.out.println("第二次gc"); obj = null; //不可复活 System.gc(); Thread.sleep(1000); if(obj == null){ System.out.println("obj 是 null"); }else{ System.out.println("obj 可用"); } }}
结果:
CanReliveObj finalize called
obj 可用 第二次gc obj 是 null说明JVM不管程序员手动调用finalize,JVM它就是执行一次finalize方法。执行finalize方法完毕后,GC会再次进行二轮回收,去判断该对象是否可达,若不可达,才进行回收。
建议:避免使用finalize方法!
太复杂了,还是让系统照管比较好。可以定义其它的方法来释放非内存资源。建议使用try-catch-finally来替代它执行清理操作。
如果手动调用了finalize,很容易出错。且它执行的优先级低,何时被调用,不确定——也就是何时发生GC不确定,因为只有当内存告急时,GC才工作,即使GC工作,finalize方法也不一定得到执行,这是由于程序中的其他线程的优先级远远高于执行finalize()的线程优先级。 因此当finalize还没有被执行时,系统的其他资源,比如文件句柄、数据库连接池等已经消耗殆尽,造成系统崩溃。且垃圾回收和finalize方法的执行本身就是对系统资源的消耗,有可能造成程序的暂时停止,因此在程序中尽量避免使用finalize方法。
先不说了,先看看JVM的垃圾回收器吧,先看一种最古老的收集器——串行收集器
最古老,最稳定,效率高,但是串行的最大问题就是停顿时间很长!因为串行收集器只使用一个线程去回收,可能会产生较长的停顿现象。我们可以使用参数-XX:+UseSerialGC,设置新生代、老年代使用串行回收,此时新生代使用复制算法,老年代使用标记-压缩算法(标记-压缩算法首先需要从根节点开始,对所有可达对象做一次标记。但之后,它并不简单的清理未标记的对象,而是将所有的存活对象压缩到内存的一端。之后,清理边界外所有的空间。有效解决内存碎片问题)。
因为串行收集器只使用一个线程去回收,可能会产生较长的停顿现象。
还有一种收集器叫并行收集器(两种并行收集器)
注意:新生代的多线程回收不一定快!看在多核还是单核,和具体环境。、
最后看一个很重要的收集器-CMS(并发标记清除收集器Concurrent Mark Sweep)收集器
顾名思义,它在老年代使用的是标记清除算法,而不是标记压缩算法,也就是说CMS是老年代收集器(新生代使用ParNew),所谓并发标记清除就是CMS与用户线程一起执行。标记-清除算法与标记-压缩相比,并发阶段会降低吞吐量,使用参数-XX:+UseConcMarkSweepGC打开。
CMS运行过程比较复杂,着重实现了标记的过程,可分为:
可以使用-XX:CMSInitiatingOccupancyFraction设置触发CMS GC的阈值,设置空间内存占用到多少时,去触发GC,如果不幸内存预留空间不够,就会引起concurrent mode failure。
可以使用-XX:+ UseCMSCompactAtFullCollection, Full GC后,进行一次整理,而整理过程是独占的,会引起停顿时间变长。
从三个方面考虑: