Java引用类型分为强引用、软引用、弱引用、虚引用,本文对四种引用类型进行分析
强引用
强引用:日常开发中最常见的引用类型,直接通过new来创建对象,如果放任不管对象将不会被回收当对象不断增加不做释放就会造成OOM,所以需要手动去释放内存再等待GC的回收,也可以通过类似Activity有生命周期的类伴随类销毁回收一并回收掉。
//new出对象object
Object object = new Object();
//将object对象引用链断开等待GC回收
object = null ;
软引用
软引用(SoftReference):软引用用来存放不是必须存在但是还有用的对象,一般来说软引用对象不会被回收,只有在内存不足时会选择释放掉软引用内存,来满足程序正常运行。举个例子来描述Activity页面上呈现几张图片,可能会执行其他耗内存操作,比如从APP中切出去到其他耗内存的动作时,图片是没有在页面显示的,所以图片的内存可以有也可以没有(因为页面也看不见嘛有没有都一样),但是当从其他任务执行结束回到APP中时,还需要图片的正常显示,这种情况的图片就是不是必须存在但是还有用的对象。如果使用强引用的话,当APP切换到后台但是内存不足时就会抛出OOM,但是使用软引用存放对象的话,当内存不足时会优先去回收软引用的对象这样就会有多余的内存供给调用,这样就会减少因内存不足而引发的OOM。
弱引用
弱引用(WeakReference):弱引用不管内存足够或是不足够都可以被回收的一种引用类型,第一次GC扫描到会进行标记,第二次扫描直接进行回收。下面用代码展示下弱引用:
//模拟弱引用效果,先创建一个对象一会将对象回收
Object weakObject = new Object() ;
//创建一个引用队列
ReferenceQueue referenceQueue = new ReferenceQueue();
//创建弱引用
WeakReference<Object> weakReference = new WeakReference<>(weakObject,referenceQueue);
//打印弱引用中的对象 第一次打印
System.out.println("weakReference: "+ weakReference.get());
//打印引用队列中对象 第二次打印
System.out.println("referenceQueue: "+referenceQueue.poll());
//将对象设置为null
weakObject = null ;
//手动GC回收一下
System.gc();
//因为这里方便调试看回收效果所以等待两秒
Thread.sleep(2000);
//打印弱引用中的对象 第三次打印
System.out.println("weakReference: "+ weakReference.get());
//打印引用队列中对象 第四次打印
System.out.println("referenceQueue: "+referenceQueue.poll());
这里模拟对象被回收过程,然后展示弱引用可以存储对象信息并可以使用对象,当GC触发时对象被回收引用队列内保存回收引用信息。来看下打印结果:
不难看出弱引用是可以存储对象信息并使用的第一次打印是Object对象(java.lang.Object),而在没触发GC的时候引用队列为null,但触发GC回收之后,引用对象被回收所以第三次打印医用对象信息为null,最后第四次打印因为对象被回收但是回收引用的信息会存储在引用队列中,所以第四次打印可以打印出回收引用信息(java.lang.ref.WeakReference)。
虚引用
虚引用(PhantomReference):虚引用一般被称为幽灵、幻影引用,虚引用不对生存造成任何影响,仅用于跟踪GC的回收通知,一般开发不适用虚引用,在特定的情况下可能使用就是需要记录GC何时回收对象信息,那么虚引用就可能会排上用场。下面用代码展示下虚引用:
//模拟虚引用效果,先创建一个对象一会将对象回收
Object phantomObject = new Object() ;
//创建一个引用队列
ReferenceQueue referenceQueue = new ReferenceQueue();
//创建虚引用
PhantomReference<Object> phantomReference = new PhantomReference<>(phantomObject,referenceQueue);
//打印弱引用中的对象 第一次打印
System.out.println("phantomReference: "+ phantomReference.get());
//打印引用队列中对象 第二次打印
System.out.println("referenceQueue: "+referenceQueue.poll());
//将对象设置为null
phantomObject = null ;
//手动GC回收一下
System.gc();
//因为这里方便调试看回收效果所以等待两秒
Thread.sleep(2000);
//打印弱引用中的对象 第三次打印
System.out.println("phantomReference: "+ phantomReference.get());
//打印引用队列中对象 第四次打印
System.out.println("referenceQueue: "+referenceQueue.poll());
这里模拟对象回收过程,然后展示虚引用可以存储对象回收信息但是虚引用并不能引用对象仅仅能记录对象回收信息,当GC触发时对象被回收引用队列内保存回收引用信息。来看下打印结果:
如果这里对比弱引用来看的话,不难看出虚引用是弱引用的降级版,因为弱引用可以引用对象实例,然而虚引用不可以引用对象实例仅用于存储对象被回收信息。
以上就是就是四种引用类型的简要介绍,对比文章内容不难看出实际上强、软、弱、虚引用的能力是一次递减。在实际开发中好好利用四种引用类型,会大大的减少开发过程中的内存溢出异常。
下一篇 将了解内存抖动是什么以及内存抖动发生的原因及常见解决办法