91名师指路-头部
91名师指路

面试题(五)强引用、软引用、弱引用、虚引用分别是什么?

由于某些原因,现在不支持支付宝支付,如需要购买源码请加博主微信进行购买,微信号:13248254750

引用的组织架构图


一:强引用(死了都不进行回收)。

(1)当内存不足,JVM开始垃圾回收,对于强引用的对象,就算是出现了OOM也不会对该对象进行回收,死都不收。

(2)强引用是我们最常见的普通对象引用,只要还有强引用指向一个对象,就能表明对象还“活着”,垃圾收集器不会碰这种对象,在java中最常见的就是强引用。把一个对象赋给一个引用变量,这个引用变量就是一个强引用。当一个对象被强引用变量引用时,它处于可达状态,它是不可能被垃圾回收机制回收的,即使该对象以后永远都不会被用到JVM也不会回收。因此强引用是造成java内存泄漏的主要原因之一。

(3)对于一个普通的对象,如果没有其他的引用关系,只要超过了引用的作用域或者显示的将相应(强)引用赋值为null,一般认为就是可以被垃圾收集的(当然具体回收时机还是要看垃圾收集策略)。


强引用演示代码

package com.mszl.gc;
/**
* 功能:强引用
* 备注:更多资料请访问 http://www.91mszl.com
* @author bobo teacher
*/
public class ReferenceDemo1 {

public static void main(String[] args) {
Object obj1=new Object(); // 这样的写法就是强引用
Object obj2=obj1; // obj2 引用赋值
obj1=null;
System.gc();

System.out.println(obj1);
System.out.println(obj2);
}


}

执行结果

null
java.lang.Object@1db9742


二:软引用(在JVM内存充足的情况下不进行回收,JVM内存不够的时候进行回收)。

(1)软引用是一种相对强引用弱化了一些引用,需要用java.lang.ref.SoftReference类实现,可以让对象豁免一些垃圾收集。

(2)对于只有软引用的对象来说,当系统内存充足时不会被回收,当系统内存不足时会被回收。

(3)软引用通常在堆内存敏感的程序中,比如高速缓存就有用到软引用,内存够用的时候就保留,不够用就回收。


软引用内存充足的情况演示,代码如下

package com.mszl.gc;

import java.lang.ref.SoftReference;

/**
* 功能:软引用
* 备注:更多资料请访问 http://www.91mszl.com
* @author bobo teacher
*/
public class ReferenceDemo2 {

// 内存充足
public static void memoryEnough(){
Object obj=new Object();
SoftReference<Object> sf=new SoftReference<Object>(obj);
System.out.println(obj);
System.out.println(sf.get());

obj=null;
System.gc();

System.out.println(obj);
System.out.println(sf.get());
}

public static void main(String[] args) {
memoryEnough();
}

}

执行结果

java.lang.Object@1db9742
java.lang.Object@1db9742
null
java.lang.Object@1db9742


软引用内存不足的情况演示,代码如下

package com.mszl.gc;

import java.lang.ref.SoftReference;

/**
* 功能:软引用
* 备注:更多资料请访问 http://www.91mszl.com
* @author bobo teacher
*/
public class ReferenceDemo2 {

// 内存不足:我们eclipse设置为 -Xms10m -Xmx10m
public static void memoryNotEnough(){
Object obj=new Object();
SoftReference<Object> sf=new SoftReference<Object>(obj);
System.out.println(obj);
System.out.println(sf.get());

obj=null;
try{
byte[] bt=new byte[30 * 1024 * 1024];
} catch(Exception ex){
ex.printStackTrace();
} finally{
System.out.println(obj);
System.out.println(sf.get());
}
}

public static void main(String[] args) {
memoryNotEnough();
}

}

执行结果

java.lang.Object@1db9742
java.lang.Object@1db9742
null
null
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
at com.mszl.gc.ReferenceDemo2.memoryNotEnough(ReferenceDemo2.java:21)
at com.mszl.gc.ReferenceDemo2.main(ReferenceDemo2.java:31)


三:弱引用(不管JVM的内存是否足够,都会进行回收)。

(1)弱引用需要用java.lang.ref.WeakReference类来实现,它比软引用的生存期更短。
(2)对于只有弱引用的对象来说,只要垃圾回收机制一运行,不管JVM的内存空间是否足够,都会回收该对象占用的内存。

弱引用演示代码

package com.mszl.gc;

import java.lang.ref.WeakReference;

/**
* 功能:弱引用
* 备注:更多资料请访问 http://www.91mszl.com
* @author bobo teacher
*/
public class ReferenceDemo3 {

public static void main(String[] args) {
Object obj=new Object();
WeakReference<Object> wr=new WeakReference<Object>(obj);

System.out.println(obj);
System.out.println(wr.get());

obj=null;
System.gc();

System.out.println(" ---------------- ");

System.out.println(obj);
System.out.println(wr.get());
}

}

执行结果

java.lang.Object@128f6ee
java.lang.Object@128f6ee
----------------
null
null

四:引用队列ReferenceQueue 

引用队列演示代码如下:

package com.mszl.gc;

import java.lang.ref.ReferenceQueue;
import java.lang.ref.WeakReference;

/**
* 功能:引用队列
* 备注:更多资料请访问 http://www.91mszl.com
* @author bobo teacher
*/
public class ReferenceDemo5 {

public static void main(String[] args) throws InterruptedException {
Object obj=new Object();
ReferenceQueue<Object> queue=new ReferenceQueue<Object>(); // 引用队列
WeakReference<Object> wf=new WeakReference<Object>(obj, queue); // 弱引用

System.out.println(obj);
System.out.println(wf.get());
System.out.println(queue.poll());

System.out.println("=============");
obj=null;
System.gc();
Thread.sleep(1000);

System.out.println(obj);
System.out.println(wf.get());
System.out.println(queue.poll());
}


}

执行结果

java.lang.Object@128f6ee
java.lang.Object@128f6ee
null
=============
null
null
java.lang.ref.WeakReference@166afb3


五:虚引用。

(1)虚引用需要java.lang.ref.PhantomReference类来实现。

(2)顾名思义,就是形同虚设,与其他几种引用都不同,虚引用并不会决定对象的生命周期。如果一个对象仅持有虚引用,那么它就和没有任何引用一样,在任何时候都可能被垃圾回收器回收,它不能单独使用也不能通过它访问对象,虚引用必须和引用队列(ReferenceQueue)联合使用。

(3)虚引用的主要作用是跟踪对象被垃圾回收的状态。仅仅是提供了一种确保对象被finalize以后,做某些事情的机制。PhantomReference的get方法总是返回null,因此无法访问对应的引用对象。其意义在于说明一个对象已经进入finalization阶段,可以被gc回收,用来实现比finalization机制更灵活的回收操作。

(4)换句话说,设置虚引用关联的唯一目的,就是在这个对象被收集器回收的事情收到一个系统通知或者后续添加进一步的处理。java技术允许使用finalize()方法在垃圾收集器将对象从内存中清除出去之前做必要的清理工作。

虚引用演示代码

package com.mszl.gc;

import java.lang.ref.PhantomReference;
import java.lang.ref.ReferenceQueue;

/**
* 功能:虚引用
* 备注:更多资料请访问 http://www.91mszl.com
* @author bobo teacher
*/
public class ReferenceDemo6 {

public static void main(String[] args) throws InterruptedException {
Object obj=new Object();
ReferenceQueue<Object> queue=new ReferenceQueue<Object>(); // 引用队列
PhantomReference<Object> pf=new PhantomReference<Object>(obj, queue); // 虚引用

System.out.println(obj);
System.out.println(pf.get());
System.out.println(queue.poll());

System.out.println("=============");
obj=null;
System.gc();
Thread.sleep(1000);

System.out.println(obj);
System.out.println(pf.get());
System.out.println(queue.poll());
}


}

执行结果

java.lang.Object@166afb3
null
null
=============
null
null
java.lang.ref.PhantomReference@b5dac4


总结:

(1)java提供了4种引用类型,在垃圾回收的时候,都有自己各自的特点。ReferenceQueue是用来配合引用工作的,没有referenceQueue一样可以运行。

(2)创建引用的时候可以指定关联的队列,当GC释放对象内存的时候,会将引用加入到引用队列,如果程序发现某个虚引用已经被加入到引用队列,那么就可以在所引用对象的内存被回收之前采取必要的行动,这相当于是一种通知机制。

(3)当关联的引用队列中有数据的时候,意味着引用指向的堆内存中的对象被回收。通过这种方式,JVM允许我们在对象被销毁后做一些我们自己想做的事情。


2019-12-06 18:31:33     阅读(1254)

名师出品,必属精品    https://www.91mszl.com

联系博主    
用户登录遮罩层
x

账号登录

91名师指路-底部