四种引用
- 强引用 (Strong Reference)
- 软引用 (Soft Reference)
- 弱引用 (Weak Reference)
- 虚引用 (Phantom Reference)
以上引用强度依次变弱,从引用对象到gc root 节点的一条链路上引用强度以最弱的为准,多条链路的引用强度以最强的为准
1. 强引用 (Strong Reference)
Test test = new Test();
2. 软引用(Soft Reference)
特点:使用软引用包裹的对象,如果该对象的引用强度为软引用则会发生gc且内存不足时被回收
@Test
public void softReference() {
byte[] bytes1 = new byte[1024 * 1024 * 128];
SoftReference<byte[]> weakReference = new SoftReference<>(bytes1);
assertSame(bytes1, weakReference.get());
bytes1 = null;
System.out.println("before gc");
byte[] bytes2 = new byte[1024 * 1024 * 128];
System.out.println("after gc");
// 如果gc时内存不足
assertNull(weakReference.get());
}
增加启动参数
-Xmx256m -Xmn256m -XX:+PrintGCDetails -XX:+PrintGCDateStamps
企业微信截图_15326105016656.png
3 弱引用 (Weak Reference)
特点:使用弱引用包裹的对象,如果该对象的引用强度为弱引用则会在发生gc被回收
@Test
public void weakReference() {
Object referent = new Object();
WeakReference<Object> weakReference = new WeakReference<Object>(referent);
assertSame(referent, weakReference.get());
referent = null;
System.gc();
// 一旦没有指向 referent 的强引用, weak reference 在 GC 后会被自动回收
assertNull(weakReference.get());
}
虚应用 (Phantom Reference)
虚引用是最有意思的一个
其无论在任何适合 调用 get 方法获取到的对象都是 null
他不像软引用、弱引用会自动回收内存,虚引用的存在更倾向于发送通知,虚引用被确定可以回收时将自己放入到 Reference 的 pending list 中。
次数 ReferenceHandler 线程发现 pending list 中存在对象,则执行该对象的清理方法。等到下次gc时将该对象移除。
以下代码为网上获取到的
public static void main(String[] args) throws Exception {
ReferenceQueue<Test> queue = new ReferenceQueue<>();
Thread moniterThread = new Thread(() -> {
// 监视线程,随时检查引用队列,一旦发现引用就会打印出来
for (; ; ) {
Reference<? extends Test> ref = queue.poll();
if (ref != null) {
System.out.printf("%s加入引用队列%n", ref.getClass().getSimpleName());
}
try {
Thread.sleep(0);
} catch (InterruptedException e) {
break;
}
}
});
moniterThread.start();
Test test = new Test();
WeakReference<Test> weakReference = new WeakReference<Test>(test, queue);
PhantomReference<Test> phantomReference = new PhantomReference<Test>(test, queue);
// 去除强引用
test = null;
System.out.println(">> 第一次gc <<");
System.gc();
// 这里等待一段时间,保证引用进入队列,和finalize()方法执行
Thread.sleep(100);
System.out.println("\n>> 第二次gc <<");
System.gc();
assert weakReference != null && phantomReference != null;
moniterThread.interrupt();
}
public static class Test {
@Override
protected void finalize() throws Throwable {
System.out.println("== finalize() ==");
}
}
程序执行情况如下
企业微信截图_1532611346661.png
该博客该出的解释为
1532611446(1).png那么this逃逸呢?
public class PhantomReferenceSaveOneselfTest {
static volatile Test test = new Test();
public static void main(String[] args) throws Exception {
ReferenceQueue<Test> queue = new ReferenceQueue<>();
Thread monitorThread = new Thread(() -> {
// 监视线程,随时检查引用队列,一旦发现引用就会打印出来
for (; ; ) {
Reference<? extends Test> ref = queue.poll();
if (ref != null) {
System.out.printf("%s 加入引用队列%n", ref.getClass().getSimpleName());
}
try {
Thread.sleep(0);
} catch (InterruptedException e) {
break;
}
}
});
monitorThread.start();
PhantomReference<Test> phantomReference = new PhantomReference<Test>(test, queue);
// 去除强引用
test = null;
System.out.println(">> 第一次gc <<");
System.gc();
// 这里等待一段时间,保证引用进入队列,和finalize()方法执行
Thread.sleep(100);
System.out.println("\n>> 第二次gc <<");
System.gc();
Thread.sleep(100);
test = null;
System.out.println("\n>> 第三次gc <<");
System.gc();
Thread.sleep(100);
assert phantomReference != null;
monitorThread.interrupt();
}
public static class Test {
private byte[] bytes = new byte[1024 * 1024 * 2];
@Override
protected void finalize() throws Throwable {
System.out.println("== finalize() ==");
test = this;
}
}
}
企业微信截图_15326119672211.png
网友评论