JVM是Java虚拟机的缩写,Java虚拟机是一种在计算机上运行Java字节码的虚拟机。Java虚拟机管理内存时,通常使用四种引用类型:强引用、软引用、弱引用和虚引用。这些引用类型的区别在于它们对对象的生命周期和垃圾回收的影响。
强引用(Strong Reference)
强引用是默认的引用类型。如果一个对象具有强引用,即使内存空间不足,垃圾回收器也不会回收该对象,除非该对象没有被任何引用所引用。如果一个对象的强引用变为null,则该对象成为垃圾,可能在以后的某个时间被垃圾回收器回收。
示例代码:
Object obj = new Object(); // 创建一个对象
Object strongRef = obj; // 强引用指向该对象
obj = null; // 解除原来的引用
软引用(Soft Reference)
软引用是一种不太强的引用类型,如果一个对象只有软引用,则在内存空间不足时,垃圾回收器会尝试回收该对象。软引用通常用于缓存中,以便在内存不足时可以清除不必要的缓存对象。可以使用java.lang.ref.SoftReference来创建一个软引用。
示例代码:
Object obj = new Object(); // 创建一个对象
SoftReference<Object> softRef = new SoftReference<>(obj); // 软引用指向该对象
obj = null; // 解除原来的引用
弱引用(Weak Reference)
弱引用也是一种不太强的引用类型,如果一个对象只有弱引用,则在下一次垃圾回收时,垃圾回收器将回收该对象,无论内存空间是否充足。可以使用java.lang.ref.WeakReference来创建一个弱引用。
示例代码:
Object obj = new Object(); // 创建一个对象
WeakReference<Object> weakRef = new WeakReference<>(obj); // 弱引用指向该对象
obj = null; // 解除原来的引用
虚引用(Phantom Reference)
虚引用是最不强的引用类型,它不能用于检索对象,也不能保留对象存活。它的唯一作用是当对象被垃圾回收时,虚引用将被添加到引用队列中,以便在对象被回收时执行一些特定操作,例如清除对该对象的引用。可以使用java.lang.ref.PhantomReference来创建一个虚引用。
示例代码:
Object obj = new Object(); // 创建一个对象
ReferenceQueue<Object> queue = new ReferenceQueue<>(); // 创建一个引用队列
PhantomReference<Object> phantomRef = new PhantomReference<>(obj, queue); // 虚引用指向该对象
obj = null; // 解除原来的引用
总结对比
引用类型 | 是否可以被回收 | 是否有get()方法 | 是否有构造方法 |
---|---|---|---|
强引用 | 否 | 是 | 是 |
软引用 | 内存不足时可以被回收 | 是 | 是 |
弱引用 | 只要垃圾回收器工作就会被回收 | 是 | 是 |
虚引用 | 无法通过虚引用访问到对象,垃圾回收器回收对象时将信息放到ReferenceQueue | 否 | 是 |
可以通过以下代码检查引用对象是否被回收:
System.out.println("Object from soft reference: " + softRef.get()); // 检查软引用对象是否被回收
System.out.println("Object from weak reference: " + weakRef.get()); // 检查弱引用对象是否被回收
System.out.println("Object from phantom reference: " + phantomRef.get()); // 检查虚引用对象是否被回收
注意:以上代码只是示例,实际使用中应该根据具体情况进行引用类型的选择和使用。另外,需要注意的是,虚引用必须与引用队列一起使用,否则将没有任何作用。可以使用以下代码检查引用队列中是否有虚引用对象:
Reference<?> ref = null;
while ((ref = queue.poll()) != null) {
System.out.println("Object from phantom reference is enqueued: " + ref);
}
在上面的代码中,poll()方法用于从引用队列中获取一个引用对象。如果队列为空,则返回null。如果队列中有对象,则返回引用对象。可以在程序的适当位置加入该代码来检查虚引用对象是否被回收。
以下是一个简单的使用四种引用类型的例子:
public class ReferenceExample {
public static void main(String[] args) {
// 强引用
Object obj1 = new Object();
// 软引用
SoftReference<Object> obj2 = new SoftReference<>(new Object());
// 弱引用
WeakReference<Object> obj3 = new WeakReference<>(new Object());
// 虚引用
ReferenceQueue<Object> queue = new ReferenceQueue<>();
PhantomReference<Object> obj4 = new PhantomReference<>(new Object(), queue);
// 对象不再被引用
obj1 = null;
obj2 = null;
obj3 = null;
obj4 = null;
// 垃圾回收器运行
System.gc();
// 打印引用状态
System.out.println("obj1 is " + (obj1 == null ? "null" : "not null"));
System.out.println("obj2 is " + (obj2.get() == null ? "null" : "not null"));
System.out.println("obj3 is " + (obj3.get() == null ? "null" : "not null"));
System.out.println("obj4 is " + (queue.poll() == null ? "null" : "not null"));
}
}
总之,了解这些引用类型的差异可以帮助开发人员更好地管理内存和垃圾回收。在实际开发中,应根据具体需求选择适当的引用类型。