- 强:即使OOM也不回收
- 软:内存溢出前回收
- 弱:只要垃圾收集就死
- 虚:对垃圾收集没关系,只有得到通知(插眼,也操作不了对象、只能看到它还活着)
一、软引用
代码示例:
public class Softy {//-Xms20M -Xmx20Mpublic 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设置成nullt.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对象就是引用直接内存}
}