JVM 中都有哪些引用类型?
关联课程内容
- 基础篇-软引用
- 基础篇-弱虚终结器引用
回答路径
强引用
软引用
弱引用
虚引用
终结器引用
强引用,JVM中默认引用关系就是强引用,即是对象被局部变量、静态变量等GC Root关联的对象引用,只要这层关系存在,普通对象就不会被回收。
package q5reference;
import java.util.ArrayList;
import java.util.List;
//-Xmx10m -verbose:gc
public class StrongReferenceDemo {
private static int _1MB = 1024 * 1024 * 1;
public static void main(String[] args) {
List<Object> objects = new ArrayList<>();
while (true){
byte[] bytes = new byte[_1MB];
//强引用
objects.add(bytes);
}
}
}
强引用的对象不会被回收掉,所以会出现内存溢出:
软引用,软引用相对于强引用是一种比较弱的引用关系,如果一个对象只有软引用关联到它,当程序内存不足时,就会将软引用中的数据进行回收。软引用主要在缓存框架中使用。
package q5reference;
import java.lang.ref.SoftReference;
import java.util.ArrayList;
import java.util.List;
//-Xmx10m -verbose:gc
public class SoftReferenceDemo {
private static int _1MB = 1024 * 1024 * 1;
public static void main(String[] args) {
List<SoftReference> objects = new ArrayList<>();
for (int i = 0; i < 10; i++) {
byte[] bytes = new byte[_1MB];
//软引用
SoftReference<byte[]> softReferences = new SoftReference<byte[]>(bytes);
//软引用对象放入集合中
objects.add(softReferences);
System.out.println(i);
}
//有一部分对象因为内存不足,已经被回收了
for (SoftReference softReference : objects) {
System.out.println(softReference.get());
}
}
}
内存不足时,触发了垃圾回收。
所以前几个对象已经被回收了,但是后边几个会保留下来:
弱引用,弱引用的整体机制和软引用基本一致,区别在于弱引用包含的对象在垃圾回收时,不管内存够不够都会直接被回收,弱引用主要在ThreadLocal中使用。
package q5reference;
import java.lang.ref.SoftReference;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.List;
//-Xmx100m -verbose:gc
public class WeakReferenceDemo {
private static int _1MB = 1024 * 1024 * 1;
public static void main(String[] args) {
List<WeakReference<byte[]>> objects = new ArrayList<>();
System.out.println("-------------------");
for (int i = 0; i < 10; i++) {
byte[] bytes = new byte[_1MB];
//弱引用
WeakReference<byte[]> weakReference = new WeakReference<byte[]>(bytes);
//弱引用对象放入集合中
objects.add(weakReference);
}
//设置一个强引用
byte[] last = objects.get(9).get();
//手动执行一次垃圾回收,弱引用对象只要没有强引用,就会被直接回收
System.gc();
System.out.println("-------------------");
for (WeakReference softReference : objects) {
System.out.println(softReference.get());
}
}
}
手动触发垃圾回收之后,前9个都被回收了,最后一个由于存在强引用会保留下来:
虚引用(幽灵引用/幻影引用),不能通过虚引用对象获取到包含的对象。虚引用唯一的用途是当对象被垃圾回收器回收时可以接收到对应的通知。直接内存中为了及时知道直接内存对象不再使用,从而回收内存,使用了虚引用来实现。
package q5reference;
import java.lang.ref.PhantomReference;
import java.lang.ref.Reference;
import java.lang.ref.ReferenceQueue;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.List;
//-Xmx10m -verbose:gc
public class PhantomReferenceDemo {
private static int _1MB = 1024 * 1024 * 1;
public static void main(String[] args) {
ReferenceQueue<byte[]> queue = new ReferenceQueue();
byte[] bytes = new byte[_1MB];
MyPhantomReference phantomReference = new MyPhantomReference(bytes, queue);
//去除强引用
bytes = null;
//执行垃圾回收
System.gc();
//查看队列
MyPhantomReference ref = (MyPhantomReference) queue.poll();
//清理
ref.clean();
}
}
class MyPhantomReference extends PhantomReference<byte[]>{
public void clean(){
System.out.println("清理...");
}
public MyPhantomReference(byte[] referent, ReferenceQueue<byte[]> q) {
super(referent, q);
}
}
对象回收之后虚引用对象会进入队列,这样就可以获取对象执行指定的方法了。
终结器引用,终结器引用指的是在对象需要被回收时,终结器引用会关联对象并放置在Finalizer类中的引用队列中,在稍后由一条由FinalizerThread线程从队列中获取对象,然后执行对象的finalize方法,在对象第二次被回收时,该对象才真正的被回收。
package q5reference;
import java.io.IOException;
//-verbose:gc
public class FinalizeReferenceDemo {
public static void main(String[] args) throws IOException {
Demo demo = new Demo();
demo = null;
System.gc();
System.in.read();
}
}
class Demo{
@Override
protected void finalize() throws Throwable {
System.out.println("触发finalize");
super.finalize();
}
}
对象回收时,触发了finalize方法:
上次更新: 2025/03/09, 18:29:07