Java 中的强引用、软引用、弱引用、虚引用、引用队列
Java GC 面试 About 7,526 words强引用
不会被垃圾回收,OOM
也不会对该对象进行回收。因此强引用也是造成Java
内存泄漏的主要原因之一。
new
出来的对象为强引用,obj2
指向obj1
后obj2
也就拥有了Object
对象的内存地址,obj2
也是强引用。
public static void main(String[] args) {
Object obj1 = new Object();
Object obj2 = obj1;
obj1 = null;
System.gc();
System.out.println("obj1=" + obj1);
System.out.println("obj2=" + obj2);
}
可以看到垃圾回收不会回收强引用。
obj1=null
obj2=java.lang.Object@1540e19d
软引用
内存足够的情况的下,不会回收,内存不够的情况下,会回收。
软引用通常用在内存敏感的程序中,如高速缓存就用到了软引用,MyBatis
也有用到软引用做缓存。
内存足够
public static void memoryEnough() {
Object obj1 = new Object();
SoftReference<Object> softReference = new SoftReference<>(obj1);
System.out.println("obj1=" + obj1);
System.out.println("obj1 in soft reference=" + softReference.get());
System.out.println("soft reference=" + softReference);
obj1 = null;
System.gc();
System.out.println("------------ Memory Enough After GC ------------");
System.out.println("obj1=" + obj1);
System.out.println("obj1 in soft reference=" + softReference.get());
System.out.println("soft reference=" + softReference);
}
obj1=java.lang.Object@1540e19d
obj1 in soft reference=java.lang.Object@1540e19d
soft reference=java.lang.ref.SoftReference@677327b6
------------ Memory Enough After GC ------------
obj1=null
obj1 in soft reference=java.lang.Object@1540e19d
soft reference=java.lang.ref.SoftReference@677327b6
内存不足
启动时添加-Xmx5m
限制最大内存,再分配一个30M
的字节数组人为制造OOM
。
// -Xms5m -Xmx5m
public static void memoryNotEnough() {
Object obj1 = new Object();
SoftReference<Object> softReference = new SoftReference<>(obj1);
System.out.println("obj1=" + obj1);
System.out.println("obj1 in soft reference=" + softReference.get());
System.out.println("soft reference=" + softReference);
obj1 = null;
System.out.println("------------ Memory Not Enough OOM ------------");
try {
byte[] bytes = new byte[30 * 1024 * 1024]; // 30MB 内存
} catch (Exception e) {
e.printStackTrace();
} finally {
System.out.println("obj1=" + obj1);
System.out.println("obj1 in soft reference=" + softReference.get());
System.out.println("soft reference=" + softReference);
}
}
可以看到obj1
在软引用中的对象被回收了。
注意:softReference
自身是new
出来的,所以softReference
是强引用,不会被回收。回收的是softReference
中包裹的对象obj1
。
obj1=java.lang.Object@1540e19d
obj1 in soft reference=java.lang.Object@1540e19d
soft reference=java.lang.ref.SoftReference@677327b6
------------ Memory Not Enough OOM ------------
obj1=null
obj1 in soft reference=null
soft reference=java.lang.ref.SoftReference@677327b6
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
at SoftReferenceDemo.memoryNotEnough(SoftReferenceDemo.java:36)
at SoftReferenceDemo.main(SoftReferenceDemo.java:48)
弱引用
只要垃圾回收机制一运行,不管JVM
内存是否足够,都会回收弱引用中的对象。
public static void main(String[] args) {
Object obj1 = new Object();
WeakReference<Object> weakReference = new WeakReference<>(obj1);
System.out.println("obj1=" + obj1);
System.out.println("obj1 in weak reference=" + weakReference.get());
System.out.println("weak reference=" + weakReference);
obj1 = null;
System.gc();
System.out.println("------------ After GC ------------");
System.out.println("obj1=" + obj1);
System.out.println("obj1 in weak reference=" + weakReference.get());
System.out.println("weak reference=" + weakReference);
}
同样:weakReference
自身是new
出来的,所以weakReference
是强引用,不会被回收。回收的是weakReference
中包裹的对象obj1
。
obj1=java.lang.Object@1540e19d
obj1 in weak reference=java.lang.Object@1540e19d
weak reference=java.lang.ref.WeakReference@677327b6
------------ After GC ------------
obj1=null
obj1 in weak reference=null
weak reference=java.lang.ref.WeakReference@677327b6
注意:因为运行中的线程是GCRoot
,所以及时置为null
了,也不会被回收。具体表现为,虚引用一直持有运行中的Thread
的引用,无论是否GC
。
Thread thread1 = new Thread(() -> {
System.out.println("111111111");
while (true) {
try {
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("22222222222");
}
});
thread1.start();
WeakReference<Thread> wr = new WeakReference<>(thread1);
thread1 = null;
System.gc();
System.out.println("------------ After GC ------------");
System.out.println("weak reference=" + wr.get());
输出:
------------ After GC ------------
111111111
weak reference=Thread[Thread-0,5,main]
22222222222
22222222222
虚引用
如同和没有任何引用一样,任何时候都可能被垃圾回收,虚引用不能单独使用也不能通过它访问对象,虚引用必须和引用队列ReferenceQueue
联合使用。
虚引用主要作用是跟踪对象被垃圾回收的状态,仅仅提供了一种确保对象被finalize
后,做某些事的机制。
PhantomReference
的get
方法总是返回null
。
虚引用被回收后进入引用队列,从引用队列中poll
出来的Reference
对象可以通过反射获取其内部保存的私有成员变量referent
,再通过get
方法获取保存在虚引用中的对象。
public static void main(String[] args) throws InterruptedException {
Object obj1 = new Object();
ReferenceQueue<Object> referenceQueue = new ReferenceQueue<>();
PhantomReference<Object> phantomReference = new PhantomReference<>(obj1, referenceQueue);
System.out.println("obj1=" + obj1);
System.out.println("obj1 in phantom reference=" + phantomReference.get());
System.out.println(referenceQueue.poll());
System.out.println("phantom reference=" + phantomReference);
System.out.println("-----------------------------------");
obj1 = null;
System.gc();
Thread.sleep(500);
System.out.println("obj1=" + obj1);
System.out.println("obj1 in phantom reference=" + phantomReference.get());
Reference<?> pollReference = referenceQueue.poll();
System.out.println(pollReference);
System.out.println("phantom reference=" + phantomReference);
if (pollReference != null) {
try {
Field rereferent = Reference.class.getDeclaredField("referent");
rereferent.setAccessible(true);
Object result = rereferent.get(pollReference);
System.out.println("gc will collect#" + result);
} catch (Exception e) {
e.printStackTrace();
}
}
}
输出:
obj1=java.lang.Object@1540e19d
obj1 in phantom reference=null
null
phantom reference=java.lang.ref.PhantomReference@677327b6
-----------------------------------
obj1=null
obj1 in phantom reference=null
java.lang.ref.PhantomReference@677327b6
phantom reference=java.lang.ref.PhantomReference@677327b6
gc will collect#java.lang.Object@1540e19d
引用队列
软引用、弱引用、虚引用可以在构造时传入引用队列,当引用中的对象被回收时会进入引用队列。
public static void main(String[] args) throws InterruptedException {
Object obj1 = new Object();
ReferenceQueue<Object> referenceQueue = new ReferenceQueue<>();
WeakReference<Object> weakReference = new WeakReference<>(obj1, referenceQueue);
System.out.println("obj1=" + obj1);
System.out.println("obj1 in weak reference=" + weakReference.get());
System.out.println(referenceQueue.poll());
System.out.println("weak reference=" + weakReference);
System.out.println("-----------------------------------");
obj1 = null;
System.gc();
Thread.sleep(500);
System.out.println("obj1=" + obj1);
System.out.println("obj1 in weak reference=" + weakReference.get());
System.out.println(referenceQueue.poll());
System.out.println("weak reference=" + weakReference);
}
输出:
obj1=java.lang.Object@1540e19d
obj1 in weak reference=java.lang.Object@1540e19d
null
weak reference=java.lang.ref.WeakReference@677327b6
-----------------------------------
obj1=null
obj1 in weak reference=null
java.lang.ref.WeakReference@677327b6
weak reference=java.lang.ref.WeakReference@677327b6
————        END        ————
Give me a Star, Thanks:)
https://github.com/fendoudebb/LiteNote扫描下方二维码关注公众号和小程序↓↓↓