对象存活与引用
程序员文章站
2024-03-12 15:45:50
...
垃圾收集器在对对象进行回收前,第一件事就是要确定对象是否存活
1.引用计数法
给对象添加一个引用计数器,每当有一个地方引用它时,计数器就增加1;引用失效时,计数器就减1。
任何时刻计数器为0的对象就是不可能被使用的
引用计数法实现简单,判定效率较高,但无法解决对象之间的相互引用问题,JVM并没有采用这种方法。
代码测试
package basicKnowledge.jvm.GC;
/**
* @program:summary
* @author:peicc
* @create:2019-07-15 16:50:15
**/
//引用计数法判断对象是否存活
public class IsAlive {
private Object instance=null;
private static final int _1MB=1024*1024;
private byte[]bigsize=new byte[2*_1MB];
public static void main(String[] args) {
IsAlive objectA=new IsAlive();
IsAlive objectB=new IsAlive();
objectA.instance=objectB;//相互引用
objectB.instance=objectA;//相互引用
objectA=null;
objectB=null;
System.gc();
}
}
对象objectA与对象objectB通过字段instance相互引用,除此之外,这两个对象再无引用,实际上这两个对象已经不可能再被访问 。但由于它们相互引用着对方,导致它们的引用计数都不为0,于是通过引用计数法无法再通知GC收集器回收它们
运行结果
"C:\Program Files\Java\jdk1.8.0_191\bin\java.exe" -verbose:gc -Xms20M -Xmx20M -Xmn10M -XX:+UseParNewGC -XX:+PrintGCDetails -XX:SurvivorRatio=8 -XX:MaxTenuringThreshold=15 "basicKnowledge.jvm.GC.IsAlive
[Full GC (System.gc()) [Tenured: 0K->627K(10240K), 0.0354981 secs] 6110K->627K(19456K), [Metaspace: 3209K->3209K(1056768K)], 0.0364469 secs] [Times: user=0.00 sys=0.00, real=0.04 secs]
Heap
par new generation total 9216K, used 82K [0x00000000fec00000, 0x00000000ff600000, 0x00000000ff600000)
eden space 8192K, 1% used [0x00000000fec00000, 0x00000000fec14920, 0x00000000ff400000)
from space 1024K, 0% used [0x00000000ff400000, 0x00000000ff400000, 0x00000000ff500000)
to space 1024K, 0% used [0x00000000ff500000, 0x00000000ff500000, 0x00000000ff600000)
tenured generation total 10240K, used 627K [0x00000000ff600000, 0x0000000100000000, 0x0000000100000000)
the space 10240K, 6% used [0x00000000ff600000, 0x00000000ff69cf48, 0x00000000ff69d000, 0x0000000100000000)
Metaspace used 3216K, capacity 4496K, committed 4864K, reserved 1056768K
class space used 349K, capacity 388K, committed 512K, reserved 1048576K
Java HotSpot(TM) 64-Bit Server VM warning: Using the ParNew young collector with the Serial old collector is deprecated and will likely be removed in a future release
Process finished with exit code 0
从运行结果可以看出,GC日志从6110K->627K,说明虚拟机并没有因为两个对象相互引用就没有回收它们。也说明了JVM没有采用引用计数法来判定对象是否存活
2. 可达性分析法
通过一些列被称为“GC Roots”的对象作为起始点,从这些根节点向下搜索,走过的路径称为引用链,当一个对象到达GC Roots没有任何引用链时,该对象则是不可用的。
Java语言中,可以作为GC Roots的对象有 :
- 虚拟机栈(栈帧中的本地变量表)中引用的对象
- 方法区中类静态属性引用的对象
- 方法区中常量引用的对象
- 本地方法中JNI(Native方法)中引用的对象
3.引用类型
如果reference类型的数据中存储的数值代表另一块内存的起始地址,就称这块内存代表着一个引用
-
强引用:
- 类似Objecct object=new Object();只要强引用存在,该对象永远不会被回收
-
软引用:
- 用来描述一些有用但非必需的的对象
- 在发生内存溢出之前,这些对象将会被进行第二次回收。如果这次回收还没有足够的内存,才会抛出内存溢出异常
- SoftReference类来实现软引用
-
弱引用:
- 用来描述非必须对象
- 被弱引用关联的对象智只能生存到下一次垃圾收集发生之前(无论内存是否够用)
- WeakReference类来实现弱引用
-
虚引用
- 无法通过虚引用获取一个对象的实例
- 为一个对象设置虚引用关联的唯一目的就是能在这个对象被收集器收集时收到一个系统通知
- PtantomReference类来实现虚引用