文章目录
强引用
-
普通变量赋值即为强引用,如 A a = new A();
-
通过 GC Root 的引用链,如果强引用不到该对象,该对象才能被回收
软引用(SoftReference)
-
例如:SoftReference a = new SoftReference(new A());
-
如果仅有软引用该对象时,首次垃圾回收不会回收该对象,如果内存仍不足,再次回收时才会释放对象
-
软引用自身需要配合引用队列来释放
-
典型例子是反射数据
弱引用(WeakReference)
-
例如:WeakReference a = new WeakReference(new A());
-
如果仅有弱引用引用该对象时,只要发生垃圾回收,就会释放该对象
-
弱引用自身需要配合引用队列来释放
-
典型例子是 ThreadLocalMap 中的 Entry 对象
虚引用(PhantomReference)
-
例如: PhantomReference a = new PhantomReference(new A(), referenceQueue);
-
必须配合引用队列一起使用,当虚引用所引用的对象被回收时,由 Reference Handler 线程将虚引用对象入队,这样就可以知道哪些对象被回收,从而对它们关联的资源做进一步处理
-
典型例子是 Cleaner 释放 DirectByteBuffer 关联的直接内存
演示虚引用的基本用法
public class TestPhantomReference {
public static void main(String[] args) throws IOException, InterruptedException {
ReferenceQueue<String> queue = new ReferenceQueue<>();// 引用队列
List<MyResource> list = new ArrayList<>();
list.add(new MyResource(new String("a"), queue));
list.add(new MyResource("b", queue));
list.add(new MyResource(new String("c"), queue));
System.gc(); // 垃圾回收
Thread.sleep(100);
Object ref;
while ((ref = queue.poll()) != null) {
if (ref instanceof MyResource) {
((MyResource) ref).clean();
}
}
}
static class MyResource extends PhantomReference<String> {
public MyResource(String referent, ReferenceQueue<? super String> q) {
super(referent, q);
}
// 释放外部资源的方法
public void clean() {
LoggerUtils.get().debug("clean");
}
}
}
模拟 ThreadLocalMap, 采用引用队列释放 entry 内存
public class TestWeakReference {
public static void main(String[] args) {
MyWeakMap map = new MyWeakMap();
map.put(0, new String("a"), "1");
map.put(1, "b", "2");
map.put(2, new String("c"), "3");
map.put(3, new String("d"), "4");
System.out.println(map);
System.gc();
System.out.println(map.get("a"));
System.out.println(map.get("b"));
System.out.println(map.get("c"));
System.out.println(map.get("d"));
System.out.println(map);
map.clean();
System.out.println(map);
}
// 模拟 ThreadLocalMap 的内存泄漏问题以及一种解决方法
static class MyWeakMap {
static ReferenceQueue<Object> queue = new ReferenceQueue<>();
static class Entry extends WeakReference<String> {
String value;
public Entry(String key, String value) {
super(key, queue);
this.value = value;
}
}
public void clean() {
Object ref;
while ((ref = queue.poll()) != null) {
System.out.println(ref);
for (int i = 0; i < table.length; i++) {
if(table[i] == ref) {
table[i] = null;
}
}
}
}
Entry[] table = new Entry[4];
public void put(int index, String key, String value) {
table[index] = new Entry(key, value);
}
public String get(String key) {
for (Entry entry : table) {
if (entry != null) {
String k = entry.get();
if (k != null && k.equals(key)) {
return entry.value;
}
}
}
return null;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("[");
for (Entry entry : table) {
if (entry != null) {
String k = entry.get();
sb.append(k).append(":").append(entry.value).append(",");
}
}
if (sb.length() > 1) {
sb.deleteCharAt(sb.length() - 1);
}
sb.append("]");
return sb.toString();
}
}
}