深入理解java引用
强引用
描述
强引用在java中普遍存在,类似Object object=new Object()
,任何情况下,只要这种强引用一直存在,那么这个强引用对象就不会被垃圾收集器回收
软引用(SoftReference)
描述
软引用描述着一些还有用,非必须的对象,只要被软引用管理的对象,会在内存溢出之前,会把这些对象列进回收范围之中进行第二次回收。如果这次回收还没有获取足够的内存,才会报OOM异常,但是如果所关联对象如果被强引用所指向,那么就不会被回收,就算OOM。
内存不够用时,会回收软引用,除非软引用所关联对象 被强引用所指向 ,不会被垃圾回收,就算OOM,直到OOM.
代码示例1
证明内存不够用时,软引用所关联的对象会被回收。
//JVM参数设置 -Xmx1m 当内存不够用时
public static void test1() throws InterruptedException {
byte[] bytes2=new byte[200*1024];
SoftReference<byte[]> softReference= new SoftReference<>(new byte[500*1024]);
System.out.println(softReference.get());
System.gc();
TimeUnit.SECONDS.sleep(2);
System.out.println(softReference.get());
}
//JVM参数设置 -Xmx1m 当内存够用时
public static void test2() throws InterruptedException {
SoftReference<byte[]> softReference= new SoftReference<>(new byte[1*1024]);
System.out.println(softReference.get());
System.gc();
TimeUnit.SECONDS.sleep(2);
System.out.println(softReference.get());
}
运行结果
test01执行结果
test02 执行结果
分析
当内存够用时,不会被回收,当内存不够用时,会被回收。
疑问
那如果被强引用所指向是,会被回收吗?直接报OOM?
public static void test3() throws InterruptedException {
byte[] bytes2=new byte[200*1024];
byte[] bytes3=new byte[500*1024];
SoftReference<byte[]> softReference= new SoftReference<>(bytes3);
System.out.println(softReference.get());
System.gc();
TimeUnit.SECONDS.sleep(2);
System.out.println(softReference.get());
}
运行结果
猜想证实 ,直接报OOM
总结
1.软引用所关联的对象,当内存不够用即将发生OOM时,会清楚软引用所关联的对象。
2.当软引用所关联的对象被强引用所指向时,就算要OOM了,也不会去回收这个所关联的对象。
弱引用
描述
弱引用比软引用更甚,被弱引用关联的对象
只能生存到垃圾收集回收开始,当垃圾回收器开始工作,那么垃圾回收器将会回收这一部分的对象。只要发生了GC,那么他就会被垃圾回收器所回收。
一般情况下只要发生了GC 那么就会被回收,除非被强引用所指向弱引用关联对象,那么不会被回收
代码示例1
被引用对象只能生存到垃圾回收器下一次垃圾收集开始
public static void test01() throws InterruptedException {
WeakReference<Car> weakReference = new WeakReference<>(new Car());
System.out.println(weakReference.get());
System.gc();
TimeUnit.SECONDS.sleep(2);
System.out.println(weakReference.get());
}
static class Car {
}
运行结果
结论
被弱引用关联的对象 只能生存到垃圾回收器下一次垃圾收集开始
代码实例2
public static void test021() throws InterruptedException {
WeakReference<Object> weakReference = new WeakReference<>(new Object());
Object object = weakReference.get();
System.out.println(object);
System.gc();
TimeUnit.SECONDS.sleep(2);
Object object2 = weakReference.get();
System.out.println(object2);
}
运行结果
分析
对比代码实例2 有什么不同呢?为什么没有回收掉呢?
不同点:
1.实例2 中Object object 指向了 关联对象,意思是 在栈中分配了一个强引用指向弱引用所关联的对象
2 当垃圾回收,进行是否是垃圾判断,可达性分析时,由于Object 强引用指向了弱引用所关联的对象,此时认为该对象可达,所以没有进行回收。
那么如何让其被回收呢?上码
public static void test03() throws InterruptedException {
WeakReference<Object> weakReference = new WeakReference<>(new Object());
Object object = weakReference.get();
System.out.println(object);
object = null;
System.gc();
TimeUnit.SECONDS.sleep(2);
Object object2 = weakReference.get();
System.out.println(object2);
}
运行结果
分析
为什么将强引用置为空就能够被回收呢?
还是回到 上面的分析2 中,当垃圾回收器,进行垃圾回收判断时,此时的强引用已经被置为空,认为其不可达了,就和代码示例1是一样的了,所以判定为垃圾对象,所以进行了回收。
思考题:下面代码的运行结果
public static void test04() throws InterruptedException {
Object objectF = new Object();
WeakReference<Object> weakReference = new WeakReference<>(objectF);
System.out.println(weakReference.get());
objectF = null;
System.gc();
TimeUnit.SECONDS.sleep(2);
Object object2 = weakReference.get();
System.out.println(object2);
}
总结
1.当弱引用所关联的对象,没有被强引用所指向时,弱引用所关联的对象只能存活到垃圾收集器开始收集时。
2.当弱引用所关联的对象,被强引用所指向时,弱引用所关联的对象是不能被垃圾收集器所回收的,因为在垃圾收集器做垃圾判定时,认为该所关联的对象被强引用所指向,所以认为是可达的。所以是不会被回收的。
虚引用
描述
他是最弱的一种引用,一个对象是否被虚引用关联,完全不会对其生命周期产生影响,并且通过虚引用获得关联对象永远是空。为一个对象设置虚引用关联完全是为了当这个对象被垃圾回收时,进行回调,收到一个通知而已。
示例代码
public static void test01() throws InterruptedException {
ReferenceQueue<byte[]> referenceQueue=new ReferenceQueue<>();
byte[] bytes2=new byte[200*1024];
PhantomReference<byte[]> phantomReference= new PhantomReference<>(bytes2, referenceQueue);
new Thread(()->{
Reference ref;
while((ref=referenceQueue.poll())==null){
}
System.out.println("dddd:"+ref);
}).start();
bytes2=null;
TimeUnit.SECONDS.sleep(2);
System.out.println("开始调用GC");
System.gc();
TimeUnit.SECONDS.sleep(2);
System.out.println();
}
运行结果
分析
由此可看出 虚引用 的作用只是为了所关联的对象被垃圾回收器收集的时候,系统的回调通知而已。
总结
虚引用 是不能获取所关联的对象的,虚引用的作用就是获取所关联的对象被垃圾回收时,系统的回调。
总结
对于java引用,只要一个强引用所指向一个对象,并且这个强引用一直存在,那么就不会被垃圾回收器所回收
- 强引用
只要这个强引用一直存在,那么就不会被垃圾回收器回收 - 软引用
- 软引用所关联的对象 一般生命止于 即将发生OOM时的那个时刻,当内存不够使用时,会被垃圾回收器所回收。
- 软引用所关联的对象 被强引用所指向时,并且这个强引用一直存在,那么被关联对象那么就不会被垃圾回收器所回收。
- 弱引用
- 弱引用所关联的对象 一般生命止与即将垃圾回收时,与软引用相比,不管内存够不够,弱引用所关联的对象都将会被回收。
- 弱引用所关联的对象 被强引用所指向时,并且这个强引用一直存在,那么被关联对象那么就不会被垃圾回收器所回收。
- 虚引用
- 不能够从虚引用中获取所关联的对象 源码默认null
内存不够使用时,会被垃圾回收器所回收。 - 软引用所关联的对象 被强引用所指向时,并且这个强引用一直存在,那么被关联对象那么就不会被垃圾回收器所回收。
- 不能够从虚引用中获取所关联的对象 源码默认null
- 虚引用
- 不能够从虚引用中获取所关联的对象 源码默认null
- 虚引用完全不会影响所关联对象的生命周期,虚引用的作用完全是为了 当所关联的对象被垃圾回收器所回收时,收到系统的回调的通知。