后面几篇文章会围绕JVM相关知识进行学习与分享,本文主要阐述如何判断对象是否是垃圾对象以及判断垃圾对象的依据来展开分析。
1.判断对象可以回收的依据?
垃圾回收无非就是要对已经不再存活的对象视为垃圾进行回收,那么判断是否是垃圾对象主要有两种方式,分别为引用计数法和可达性分析法。
引用计数法:
顾名思义,对象有一个计数器,每当有新的引用则计数器加1,有引用失效则计数器减1,当该对象计数器值为0则说明对象不再被引用。
(1)优点:实现简单,判断高效。
(2)缺点:对象之间循环引用问题无法得到处理。
可达性分析法:
通过一系列"GC Roots"对象作为起始点,开始向下搜索,搜索所走过和路径称为引用链, 当一个对象到GC Roots没有任何引用链相连时(从GC Roots到这个对象不可达),则证明该对象是不可用的。
(1)GC Root对象
1.虚拟机栈(栈帧中本地变量表)中引用的对象;
2.方法区中类静态属性引用的对象;
3.方法区中常量引用的对象;
4.本地方法栈中JNI(Native方法)引用的对象;
(2)优点: 更加精确和严谨,可以分析出循环数据结构相互引用的情况
(3)缺点:需要分析大量数据,消耗大量时间,分析过程需要GC停顿(引用关系不能发生变化),即停顿所有Java执行线程(Stop The World)
2.对象引用
(1)强引用:
Object obj = new Object(); 直接new对象并且变量引用就是强引用。就算溢出了也不会被回收。没有引用指向则会被回收。只要强引用还存在,GC永远不会回收被引用的对象.
(2)软引用:
SoftReference obj = new SoftReference(new byte[1024]);
对象obj 与new byte数组则是软引用的关系。
使用System.gc的时候再heap内存足够的情况下软引用不会被回收,但是如果heap内存不够用的情况下则会被回收,比较适合做缓存使用,减少数据库压力高效处理。直到内存空间不够时(抛出OutOfMemoryError之前),才会被垃圾回收
(3)弱引用:
gc触发的情况下发现弱引用对象不管当前内存空间足够与否直接被回收。对象集成WeakReference类即可为弱引用对象。GC来了就会回收。ThreadLocal 的实现使用了弱引用。只能生存到下一次垃圾回收之前,无论内存是否足够
(4)虚引用:
用于管理堆外内存,物理内存引用,但是堆外内存JVM无法进行垃圾回收,所以虚引用再回收的时候会先进入一个待回收的队列,jvm GC回收时会单独处理虚引用的对象。开发中没用到过,因为对象get的时候 get不到具体对象。当对象被回收时通过Queue可以检测到然后清理堆外内存。
3.对象生存还是死亡
要真正宣告一个对象死亡,至少要经历两次标记过程。
(1)第一次标记:
可达性分析后GC Root发现没有任何引用的时候会被第一次标记,并且判断此对象是否有必要执行finalize()方法。程序没有覆盖finalize方法或者finalize方法已经被调用过都是没有必要执行的,所以可以被回收,反之则将对象放入F-Queue(待回收队列)中等待第二次标记。
(2)第二次标记:
GC将会对F-Queue队列中的对象进行第二次标记。而finalize方法是对象逃脱回收的最后机会,并且一个对象的finalize方法只会被系统调用一次,调用过finalize依然存活的对象则不会再次被调用。如果finalize方法中该对象与其他对象有引用则会将其移除F-Queue队列。
关注我的公众号 LearnMoreDoMore 可以及时看到更多技术分享文章(只有个人技术分享相关)。