1、强引用java
JAVA默认的引用类型,强引用,是在咱们的开发工做当中广泛存在的。若是一个对象具备强引用,当内存空间不足的时候,java虚拟机宁肯抛出OOM异常,也不会回收它来释放内存。可是咱们能够将对象显示的赋值为null,则gc认为该对象不存在引用,这时就能够回收这个对象。具体何时收集这要取决于gc的算法。若是方法的内部有一个强引用,这个引用保存在栈中,而真正的引用内容(Object)保存在堆中。当这个方法运行完成后就会退出方法栈,则引用内容的引用不存在,这个Object会被回收。算法
private static void storongReference(){ Object obj=new Object(); Object obj2=obj; obj=null; System.gc(); System.out.println(obj2); //java.lang.Object@7ea987ac }
2、软引用(SoftReference)缓存
软引用是用来描述一些非必需但仍有用的对象。在内存足够的时候,软引用对象不会被回收,只有在内存不足时,系统则会回收软引用对象,若是回收了软引用对象以后仍然没有足够的内存,才会抛出内存溢出异常。软引用一般用在对内存比较敏感的程序中,例如高速缓存区,mybatis就是用到了该方式。mybatis
/** * @Auther: XL * @Date: 2019/12/24 07:50 * @Description: -Xms10M -Xmx10M -XX:+PrintGCDetails */ public class SoftReferenceTest { private volatile static Map<String,SoftReference> cacheMap=new ConcurrentHashMap<>(); public static void main(String [] args) throws Exception{ softReferenceNotAmple(); } /** * SoftReference内存不足就回收 */ private static void softReferenceNotAmple(){ SoftReference reference; for(int i=0;i<10;i++){ reference=new SoftReference(new byte[1024*1024*2]); cacheMap.put("key:"+i,reference); } cacheMap.forEach((k,v)->{ System.out.println("key:"+k+ " value:"+v.get()); }); } }
3、弱引用(WeakReference)ide
不管内存是否足够,只要 JVM 开始进行垃圾回收,那些被弱引用关联的对象都会被回收。函数
/** * @Auther: XL * @Date: 2019/12/24 08:02 * @Description: */ public class WeakReferenceTest { private volatile static Map<String,WeakReference> cacheMap=new ConcurrentHashMap<>(); public static void main(String [] args){ weakReference(); } /** * -Xms10M -Xmx10M -XX:+PrintGCDetails * 5次循环5M内存足够使用,手动触发gc;内存被回收 */ private static void weakReference(){ WeakReference reference; for(int i=0;i<5;i++){ reference=new WeakReference(new byte[1024*1024*1]); cacheMap.put("key:"+i,reference); } System.gc(); cacheMap.forEach((k,v)->{ System.out.println("key:"+k+ " value:"+v.get()); }); } }
当一个 WeakReference 开始返回 null 时, 它所指向的对象已经准备被回收, 这时能够作一些合适的清理工做. 将一个 ReferenceQueue 传给一个 Reference 的构造函数, 当对象被回收时, 虚拟机会自动将这个对象插入到 ReferenceQueue 中, WeakHashMap 就是利用 ReferenceQueue 来清除 key 已经没有强引用的 entries.
this
4、虚引用(PhantomReference)spa
形同虚设,虚引用不会决定对象的生命周期,若是一个对象仅持有虚引用,那么他和没有任何引用同样,在任什么时候候均可能被垃圾收集器回收,他不能单独使用也不能经过他访问对象,虚引用必须和引用队列(ReferenceQueue)联合使用。3d
虚引用的做用:做用在于跟踪垃圾回收过程,在对象被收集器回收时收到一个系统通知。 当垃圾回收器准备回收一个对象时,若是发现它还有虚引用,就会在垃圾回收后,将这个虚引用加入引用队列,在其关联的虚引用出队前,不会完全销毁该对象。 因此能够经过检查引用队列中是否有相应的虚引用来判断对象是否已经被回收了。使用虚引用的目的就是为了得知对象被GC的时机,因此能够利用虚引用来进行销毁前的一些操做,好比说资源释放等。这个虚引用对于对象而言彻底是无感知的,有没有彻底同样,可是对于虚引用的使用者而言,就像是待观察的对象的把脉线,能够经过它来观察对象是否已经被回收,从而进行相应的处理。虚引用有一个很重要的用途就是用来作堆外内存的释放,DirectByteBuffer就是经过虚引用来实现堆外内存的释放的。code
/** * @Auther: XL * @Date: 2019/12/24 08:38 * @Description: */ public class PhantomReferenceTest { public static void main(String [] args) throws Exception{ ReferenceQueue<TestObj> queue = new ReferenceQueue<>(); TestObj instanceA = new TestObj(); //建立对象 PhantomReference<TestObj> phantomRef = new PhantomReference<TestObj>(instanceA, queue); //建立phantom引用 System.out.println("gc前PhantomReference的引用:"+phantomRef.get()); System.out.println("gc前ReferenceQueue:"+queue.poll()); instanceA = null; // 再也不使用对象 System.gc(); System.out.println("第一次gc后PhantomReference的引用:"+phantomRef.get()); System.out.println("第一次gc后ReferenceQueue:"+queue.poll()); Thread.sleep(1000); System.gc(); System.out.println("第二次gc后PhantomReference的引用:"+phantomRef.get()); System.out.println("第二次gc后ReferenceQueue:"+queue.poll()); } } class TestObj{ @Override protected void finalize() throws Throwable { System.out.println("======"+this+"======"); super.finalize(); } }
ReferenceQueue通常用来与SoftReference、WeakReference或者PhantomReference配合使用,将须要关注的引用对象注册到引用队列后,即可以经过监控该队列来判断关注的对象是否被回收,从而执行相应的方法。
主要使用场景:
一、使用引用队列进行数据监控,相似前面栗子的用法。
二、队列监控的反向操做