- 强:即使OOM也不回收
- 软:内存溢出前回收
- 弱:只要垃圾收集就死
- 虚:对垃圾收集没关系,只有得到通知(插眼,也操作不了对象、只能看到它还活着)
一、软引用
代码示例:
public class Softy {
//-Xms20M -Xmx20M
public static void main(String[] args) {
SoftReference<byte[]>sr=new SoftReference<>(new byte[1024*1024*10]);
System.out.println(sr.get());
System.gc();
System.out.println(sr.get());
SoftReference<byte[]>sr1=new SoftReference<>(new byte[1024*1024*10]);
System.out.println(sr.get());
//用作缓存,场景:缓存一张图片进内存,有重要的事情就把它清除,没有就放着
}
}
使用场景:用作缓存,例如缓存一张图片进内存,有重要的事情就把它清除,没有就放着。
二、弱引用
使用场景:解决threadlocal的内存溢出问题。
1.Threadlocal怎么实现的?
每个线程有一个threadlocalmap对象,向这个map中添加 key:threadlocal对象、value:自己设置的值。不同的线程存数据时是分别向各自的map中存对象,所以threadlocal具有线程隔离性。
向这个map中放的对象是放entry,这个entry继承了弱引用类。在构造方法中entry对key(threadlocal)是被弱引用指向的。
2.threadlocal的使用场景?
spring声明式事务管理,f1()调用f2()和f3(),必须保证三个方法使用的connection相同,conection对象存放在threadlocal中,保证拿到的是一个链接,在同一个进程中回滚。
3.面试题:为什么弱引用可以防止threadlocal的内存溢出?
key对threadlocal的引用如果用强引用可能会内存泄露。将key(threadlocal)的引用设置成null,如果threadlocal是强引用就会导致上图中的key还在引用着threadlocal对象,不能进行内存回收。但是如果是弱引用就会立刻回收。
回收key后(变成null),去获取value就获取不到了。如果不做处理,依然会内存溢出。所以要调用remove()将整条entry干掉。
public class ThreadTest {
//容器,线程隔离性
static ThreadLocal<Person> t=new ThreadLocal<>();
public static void main(String[] args) {
new Thread(() -> {
try {
Thread.sleep(10);
t.set(new Person("hxq"));
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
new Thread(() -> {
try {
Thread.sleep(10);
System.out.println(t.get());
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
//把entry设置成null
t.remove();
}
static class Person{
public String name="hxq";
public Person(String name){
this.name=name;
}
}
}
三、虚引用
在某些情况下引用指向直接内存或者堆外内存,直接内存垃圾回收时,Java垃圾收集器无法管理,用虚引用将对象回收后,放到引用队列中,起到通知垃圾收集器的作用。
场景:
- NIO包,追踪垃圾回收。reference引用直接内存,直接内存垃圾回收器无法回收。需要用虚引用,做处理。
- DirectBuffer对象就是引用直接内存
public class Xuy {
private static final ReferenceQueue<Integer> Queue=new ReferenceQueue<>();
public static void main(String[] args) {
//虚引用回收之后放到引用队列里面,虚引用供垃圾回收器特殊处理
PhantomReference<Integer> phantomReference=new PhantomReference<>(new Integer(1), Queue);
System.out.println(phantomReference.get());
//NIO包,追踪垃圾回收。reference引用直接内存,直接内存垃圾回收器无法回收。需要用虚引用,做处理。
//DirectBuffer对象就是引用直接内存
}
}