四种引用类型
强引用:
强引用又称‘普通引用’,如:T t = new T();
这种引用类型永远都不会被回收。
软引用:
SoftReference<T> m = new SoftReference<>(new T());
此种引用只有在内存不足的情况下回收,一般用于缓存对象、图片等对象,用完一次就不用的场景。
弱引用:
WeakReference<T> m = new WeakReference<>(new T());
弱引用在调用 System.gc();时就会回收。
一般用在容器里,如ThreadLocal:
ThreadLocal 往里set值的时候,是往当前线程的Map 中放数据,key就是ThreadLocal对象,value是具体对象,在往map中set(确实是set)的时候,其实是一个Entry对象,这个Entry对象就继承了WeakReference类,是一个弱引用,当当前线程结束的时候,此时的key也就是ThreadLocal对象就会自动被回收。
如果这个key不是弱引用,而是强引用,在当前线程结束的时候,这个key,也就是ThreadLocal对象是不会被回收的。会导致内存泄露。
所以,使用ThreadLocal,不用以后,必须把对象remove掉。
remove的到底是谁 ?其实是value。key指向的是一个弱引用,当tl结束后,tl指向的强引用将会回收,此时key也会回收,所有value值是没办法访问到的,只有手动remove,否则会出现内存泄露,并导致OOM。
WeakHashMap???
虚引用:
虚引用主要用于堆外内存的。
PhantomReference<T> m = new PhantomReference<>(new T(),QUEUE);
这个东西是给写虚拟机(JVM)的人用的,程序员一般用不上。
垃圾回收只要看到有虚引用,二话不说,直接回收。当对象被回收的时候,会通知你,将对象的引用放入QUEUE 中,也就是说,只要队列中有引用,说明这个对象已被回收。
虚引用的回收是通过一个队列来维护的。
还有一点,虚引用里边的值是get不到的。
NIO中有个DirectByteBuffer就是堆外内存(直接内存),使用的虚引用,它不归JVM管理,而是操作系统,什么时候去回收这块堆外内存呢?可以去监听这个队列,当这个队列中有值时,就去清理堆外内存。
怎么回收堆外内存?
通过Unsafe,还有直接分配内存、释放内存的api
内存泄露和内存溢出的区别:
内存泄露可以理解为 漏掉了一块,永远不会被回收;内存溢出是指占用的内存越来越多,占不下了导致溢出。