Java中的引用类型
1.强引用
一个对象A被局部变量、静态变量引用了就产生了强引用。因为局部变量、静态变量都是被GC Root对象关联上的,所以被引用的对象A,就在GC Root的引用链上了。只要这一层关系存在,对象A就不会被垃圾回收器回收。所以只要方法不退出,局部变量就会保存当前对象A的地址,该对象就不会被回收。
public static void main(String[] args) {
ArrayList<Object> objects = new ArrayList<>();
while (true) {
//以下两行代码产生了两个引用关系,1.bytes变量 到 new byte[1024 * 1024]; 这个字节数组的引用关系,这也是一个强引用
byte[] bytes = new byte[1024 * 1024];
//2. objects集合对象 到 字节数组的关系,也是强引用
objects.add(bytes);
//每一轮while循环结束后,第一个引用关系就断开了。
//但第二个引用关系没有断开!所以 bytes数组1mb大小的内存空间是不会被回收的。
//这样就会导致每轮循环内存中增加1mb的数据,而且不能被回收
}
}
最后一次垃圾回收:回收前7873k,回收后7831k。回收前后内存差不多。说明有大量强引用在,而强引用不能被回收。最终内存不够用而报错。
2.软引用
由于软引用允许垃圾回收器在内存不足时回收对象。所以软引用放的对象一般都不是很重要的对象,否则内存不足时,这个对象一被回收,某些核心数据就没了。主要应用场景在缓存里面。
public static void main(String[] args) {
ArrayList<SoftReference> objects = new ArrayList<>();
for (int i = 0; i < 10; i++) {
byte[] bytes = new byte[1024 * 1024];
//软引用
SoftReference<byte[]> softReference = new SoftReference<>(bytes);
//将软引用对象放入集合中
objects.add(softReference);
System.out.println(i);
}
for (SoftReference softReference : objects) {//打印一下没有被回收的软引用
System.out.println(softReference.get());
}
}
注:这里设置了堆内存10mb(由于还要其他强引用占用空间,所以存不下10个1mb的字节数组),且打印垃圾回收日志
说明:可以看到前七次没有进行垃圾回收,在到下标为6时,进行垃圾回收,这个时候就会把所有软引用对象全部回收,前七个对象没有了。最后再放入7-9三个字节数组对象。
最终打印集合:前七个为null(被回收了),只有后三个了。
注:这种机制很适合缓存,因为就算缓存中软引用的数据因为内存不足被回收了,也可以去数据库中查询数据。
3.弱引用
弱引用的生命周期比软引用更短,无论内存是否充足,只要垃圾回收器开始工作,弱引用关联的对象都会被回收。弱引用适用于实现可以随时被回收的缓存数据,因为它不受内存状况的影响。
null
null
null
null
null
null
null
null
null
[B@4eec7777
进程已结束,退出代码0
执行结果:前九个为空,最后一个由于强引用存在,没有被回收。
4.虚引用
虚引用是最弱的一种引用关系,如果一个对象仅持有虚引用,那么它就和没有任何引用一样,它随时可能会被回收,在 JDK1.2 之后,用 PhantomReference 类来表示,通过查看这个类的源码,发现它只有一个构造函数和一个 get() 方法,而且它的 get() 方法仅仅是返回一个null,也就是说将永远无法通过虚引用来获取对象,虚引用必须要和 ReferenceQueue 引用队列一起使用。
如果一个对象只具有虚引用,那么它就和没有任何引用一样,随时会被JVM当作垃圾进行GC。