java中在java.lang.ref包下提供了一个Reference抽象类,它主要为了决定某些对象的生命周期,通过与垃圾收集器密切配合来实现JVM进行垃圾回收。在该包下有四个实现了Reference的子类,分别是strongReference(强引用),SoftReference(软引用),WeakReference(弱引用),PhantomReference(虚引用)。
StrongReference(强引用)
强引用就是平时使用new来创建对象生成的引用。我们可以通过人为把对象设置为null,来通知JVM在合适的时间进行垃圾回收。JVM并不强制程序员自己来把强引用对象设置为null,它会自动检查强引用对象的引用计数,如果发现该对象已经没有被引用,将会自动进行内存回收。
强引用被引用变量指向时永远不会被垃圾回收,JVM宁愿抛出OutOfMemory错误也不会回收这种对象。
private static void testStrongReference() { printMemory("Start"); // 申请100MB的内存 byte[] strong = new byte[100 * MB]; printMemory("Use 100MB"); // 回收 System.gc(); printMemory("not null GC after"); // 设置引用为null strong = null; printMemory("null GC before"); // 回收 System.gc(); printMemory("null GC after"); } private static void printMemory(String info) { long free = Runtime.getRuntime().freeMemory(); long max = Runtime.getRuntime().maxMemory(); System.out.println( info + ":" + free/MB +"MB(free)/" +max/MB +"MB(max)"); }
输出结果:
Start:254MB(free)/256MB(max) Use 100MB:152MB(free)/256MB(max) not null GC after:153MB(free)/256MB(max) null GC before:153MB(free)/256MB(max) null GC after:254MB(free)/256MB(max)
ReferenceQueue(引用队列)
保用来保存的是Reference对象,其作用在于Reference对象所引用的对象被GC回收时,该Reference对象将会被加入引用队列中的队列末尾。
常用的方法:
poll():从队列中取出一个元素,队列为空则返回nullremove():从队列中出对一个元素,若没有则阻塞至有可出队元素remove(long timeout):从队列中出对一个元素,若没有则阻塞至有可出对元素或阻塞至超过timeout毫秒;SoftReference, WeakReference和PhantomReference可以结合ReferenceQueue来追踪对象被回收的过程。
SoftReference(软引用)
如果一个对象具有软引用,内存空间足够,垃圾回收器就不会回收它;反之,如果内存空间不足了,若一个对象只有软引用,则垃圾回收器就会回收它。
使用软引用能防止内存泄露,增强程序的健壮性,可以用来构建敏感数据的缓存(如网页缓存、图片缓存等)。
软引用可以和一个引用队列一同使用,当所引用的对象被回收,软引用便被加入到引用队列。
例子1:
private static void testSoftReference() { printMemory("Start"); SoftReference<byte[]> reference = new SoftReference<byte[]>(new byte[200 * MB]); printMemory("not null GC before"); System.out.println("before gc:" + reference.get()); //通知GVM回收资源 System.gc(); printMemory("not null GC after"); System.out.println("after gc:" + reference.get()); }
输出结果:
Start:254MB(free)/256MB(max) not null GC before:53MB(free)/256MB(max) before gc:[B@70177ecd not null GC after:53MB(free)/256MB(max) after gc:[B@70177ecd
例子2:
private static void testSoftReference1() { printMemory("Start"); ReferenceQueue<byte[]> queue = new ReferenceQueue<>(); SoftReference<byte[]> reference = new SoftReference<byte[]>(new byte[200 * MB],queue); printMemory("not null GC before"); System.out.println("before gc:" + reference.get()); System.out.println("before gc. queue.poll():" + queue.poll()); //通知JVM回收资源 System.gc(); printMemory("not null GC after"); System.out.println("after gc:" + reference.get()); System.out.println("after gc. queue.poll():" + queue.poll()); // 因为当前只有53M内存可以使用,因此会jvm会回收reference已经使用了的200M内存,才能够创建100M的对象 SoftReference<byte[]> reference1 = new SoftReference<byte[]>(new byte[100 * MB]); printMemory("create another soft reference 1"); System.out.println("reference:" + reference.get()); System.out.println("reference1:" + reference1.get()); System.out.println("queue.poll():" + queue.poll()); }
输出结果:
Start:254MB(free)/256MB(max) not null GC before:53MB(free)/256MB(max) before gc:[B@70177ecd before gc. queue.poll():null not null GC after:53MB(free)/256MB(max) after gc:[B@70177ecd after gc. queue.poll():null create another soft reference 1:153MB(free)/256MB(max) reference:null reference1:[B@4769b07b queue.poll():java.lang.ref.SoftReference@cc34f4d
WeakReference(弱引用)
弱引用也是用来描述非必需对象的,当JVM进行垃圾回收时,无论内存是否充足,都会回收被弱引用关联的对象。
private static void testWeakReference() { printMemory("Start"); WeakReference<byte[]> reference = new WeakReference<byte[]>(new byte[200 * MB]); printMemory("not null GC before"); System.out.println("before gc:" + reference.get()); //通知JVM回收资源 System.gc(); printMemory("not null GC after"); System.out.println("after gc:" + reference.get()); }
输出结果:
Start:254MB(free)/256MB(max) not null GC before:53MB(free)/256MB(max) before gc:[B@70177ecd not null GC after:254MB(free)/256MB(max) after gc:null
PhantomReference(虚引用)
虚引用和前面的软引用、弱引用不同,它并不影响对象的生命周期。如果一个对象与虚引用关联,则跟没有引用与之关联一样,它get()方法永远返回null(这个应该就是被称为虚引用的原因)。
虚引用在任何时候都可能被垃圾回收器回收,必须和引用队列(ReferenceQueue)联合使用,当所引用的对象被回收,虚引用便被加入到引用队列,主要用来追踪垃圾回收过程。
例如:
private static void testPhantomReference() { printMemory("Start"); byte[] bytes = new byte[200 * MB]; ReferenceQueue<byte[]> queue = new ReferenceQueue<byte[]>(); PhantomReference<byte[]> reference = new PhantomReference<byte[]>(bytes, queue); printMemory("GC before"); System.out.println("GC before. reference:" + reference.get()); System.out.println("GC before. queue.poll(): " + queue.poll()); //断开强引用 bytes = null; System.gc(); printMemory("GC after"); System.out.println("GC after reference:" + reference.get()); System.out.println("GC after.queue.poll(): " + queue.poll()); }
输出结果:
Start:254MB(free)/256MB(max) GC before:53MB(free)/256MB(max) GC before. reference:null GC before. queue.poll(): null GC after:254MB(free)/256MB(max) GC after reference:null GC after.queue.poll(): java.lang.ref.PhantomReference@1e80bfe8
参考资料
https://www.cnblogs.com/fomin/p/10254547.html
还没有评论,来说两句吧...