Java中包含一下四种引用类型
1. 强引用 2. 软引用 3. 弱引用 4. 虚引用
1、强引用
就是普通的引用,例如: Object o = new Object()
,此时 o
就是强引用,在这种情况下,即使内存空间不足,它也不会被gc回收,而是会报OutOfMemoryError
的错误,当把 o
置为null的时候,这个时候才解除了强引用,才会被gc在合适的时间回收,例子如下:
public class M{
//该方法已被弃用,只是当作演示
@Override
protected void finalize() throws Throwable{
super.finalize();
//该方法会在gc回收的时候调用
System.out.println("finalize");
}
}
public class NormalReference {
public static void main(String[] args) {
//首先new一个对象
//强引用
M m = new M();
//然后把对象设置为空
//取消 强引用
m = null;
//手动调用垃圾回收器回收
System.gc();//此时控制台就会打印 finalize
try{
//调用read方法是为了让main方法发生阻塞
//防止main方法执行完毕退出,然后看不到打印的东西
System.in.read();
} catch (Exception e) {
e.printStackTrace();
}
}
}
2、软引用
软引用就是当内存充足的时候。它不会被垃圾回收器回收,当内存空间不够用的时候,软引用就会被垃圾回收器回收,你要理解软引用SoftReference
是一个对象,该对象里存放着数据
用途: 用来做缓存
例子如下:
public class SoftReference {
public static void main(String[] args) {
//此时new一个软对象,该对象放一个10M的byte的数组
SoftReference<byte[]> sf = new SoftReference<>(new byte[1024*1024*10]);
//此时是可以从sf中拿到数据的
System.out.println(sf.get());// [B@66133adc
//手动调用垃圾回收器回收
System.gc();
try{
//睡500毫秒
Thread.sleep(500);
} catch (Exception e) {
e.printStackTrace();
}
//此时也是可以从sf中拿到数据的
System.out.println(sf.get());// [B@66133adc
//这时,我们再new一个软对象,该对象放一个10M的byte的数组
SoftReference<byte[]> sf1 = new SoftReference<>(new byte[1024*1024*10]);
//这个时候,我我们就拿不到数据了,
//sf就会被垃圾回收器回收了,打印的就是为空
System.out.println(sf.get());// null
}
}
注意在运行的时候,需要如下设置
3、弱引用
弱引用就是不管内存中是否有空间,只要遇到垃圾回收器,就会被回收。
用途: 是为了解决某些地方的内存泄露的问题。用在 ThreadLocal
里面
弱引用例子如下:
public class WeakReference {
public static void main(String[] args) {
//new 一个弱引用,然后里面存放1M的byte数组
WeakReference<byte[]> wr = new WeakReference<>(new byte[1024 * 1024);
//此时在 wr 中是有数据的
System.out.println(wr.get());
//手动调用垃圾回收器
System.gc();
//这个时候在 wr 中是空的。
System.out.println(wr.get());
}
}
4、虚引用
虚引用会跟一个引用队列相关联使用,它的原理就是,当一个虚引用指向的对象被回收的时候,它会把一个信息添加到跟这个虚引用相关联的这个队列中。还有就是虚引用的get方法,返回的永远是 null
用途: 管理堆外内存 netty NIO
例子如下:
public class WeakReference {
private static final List<Object> list = new LinkedList<>();
//引用队列,跟虚引用相关联
private static final ReferenceQueue<M> queue = new ReferenceQueue<>();
public static void main(String[] args) {
//生成一个虚引用,用来指向M,并且与 queue队列进行绑定
PhantomReference<M> pr = new PhantomReference<>(new M(), queue);
//开启一个线程,不断的增加内存
new Thread(()->{
while (true) {
try {
//不断的给list添加数据,使内存被占光,
//导致虚引用被回收
list.add(new byte[1024 * 1024])
Thread.sleep(1000);
} catch (Exception e) {
e.printStackTrace();
}
//打印pr里面的值 ,这里是永远拿不到里面的值的
System.out.println(pr.get());
}
}).start();
//开启另一个线程,不断的从queue中去数据
new Thread(()->{
while (true) {
try {
Reference<? extends M> poll = queue.poll();
//当取出来的数据不为空的时候,说明
//虚引用指向的对象被回收了
if(poll != null) {
System.out.println("虚引用指向的对象被jvm回收了");
}
Thread.sleep(500);
} catch (Exception e) {
e.printStackTrace();
}
}
}).start();
}