下面是一个在下面引用实战中用到的公共类
public class M {
@Override
protected void finalize() throws Throwable{
System.out.println("finalize");
}
}
finalize()方法是执行gc时调用的方法。
一、强引用
- 强引用是默认的引用类型。
- 当一个对象具有强引用时,垃圾收集器不会回收该对象。
- 只有在没有任何强引用指向一个对象时,该对象才会被垃圾收集器回收。
public class T01_NormalReference {
public static void main(String[] args) throws IOException {
M m = new M();
m = null;
System.gc();
System.in.read();
}
}
执行上面程序,结果如下。结果证明M被回收了。
二、软引用
- 软引用用于描述一些还有用但不是必需的对象。
- 当内存不足时,垃圾收集器会回收软引用指向的对象。
- 可用于实现内存敏感的高速缓存。
软引用是一种用于描述一些还有用但不是必需的对象的引用类型,当内存不足时,垃圾收集器会回收软引用指向的对象。以下是一个验证软引用的示例代码:
public class T02_SoftReference {
public static void main(String[] args) {
SoftReference<byte[]> m = new SoftReference<>(new byte[1024*1024*10]);
//m = null;
System.out.println(m.get());
System.gc();
try {
Thread.sleep(500);
}catch (InterruptedException e){
e.printStackTrace();
}
System.out.println(m.get());
// 模拟内存不足的情况
try {
// 分配大量内存,让系统触发垃圾回收
byte[] memoryAlloc = new byte[1024 * 1024 * 15]; // 分配10MB的内存
} catch (OutOfMemoryError e) {
System.out.println("内存不足,系统触发了垃圾回收");
}
System.out.println(m.get());
}
}
配置程序执行的最大内存为20M,执行结果如下
在这个示例中,我们首先创建一个字符串对象,并将其放入软引用中。然后,我们清空了强引用,使字符串对象只能被软引用引用。接下来,我们模拟了内存不足的情况,分配了大量内存,这将导致系统触发垃圾回收。最后,我们再次从软引用中获取对象,并检查对象是否被回收。
运行示例代码后,你会看到当内存不足时,垃圾收集器会回收软引用中的对象,软引用变为null,表示对象已被回收。这演示了软引用在内存管理中的作用。
三、弱引用
- 弱引用用于描述非必需对象,但只要没有强引用指向它,就可能被垃圾收集器回收。
- 通常用于构建对象注册表或管理器。
弱引用是Java中的一种引用类型,当对象只被弱引用引用时,垃圾收集器会在下一次垃圾回收时回收该对象。以下是一个验证弱引用的示例代码:
public class WeakReferenceExample {
public static void main(String[] args) {
// 创建一个字符串对象,并将其放入弱引用中
String str = new String("这是一个弱引用示例");
WeakReference<String> weakRef = new WeakReference<>(str);
// 清空强引用,使字符串对象只被弱引用引用
str = null;
// 从弱引用中获取对象
String retrieved = weakRef.get();
// 打印从弱引用中获取的对象
System.out.println("从弱引用中获取的对象:" + retrieved);
// 模拟垃圾回收过程
System.gc();
// 等待一段时间以确保垃圾回收器完成回收
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
// 从弱引用中再次获取对象
retrieved = weakRef.get();
// 如果对象被回收,retrieved将为null
if (retrieved == null) {
System.out.println("对象已被回收");
} else {
System.out.println("对象仍然可用:" + retrieved);
}
}
}
运行上面程序,结果如下
在这个示例中,我们首先创建一个字符串对象,并将其放入弱引用中。然后,我们清空了强引用,使字符串对象只能被弱引用引用。接下来,我们获取弱引用中的对象,并打印出来。然后,我们模拟垃圾回收过程,并等待一段时间以确保垃圾回收器完成回收。最后,我们再次从弱引用中获取对象,并检查对象是否被回收。
运行示例代码后,你会看到当垃圾回收器执行后,弱引用中的对象被回收,因此再次从弱引用中获取的对象为null。这演示了弱引用的行为,它允许对象在没有强引用的情况下被垃圾收集。
四、虚引用
- 虚引用是最弱的引用类型。
- 它几乎不影响对象的生命周期,但允许在对象被回收前执行某些操作。
- 通常与引用队列(ReferenceQueue)一起使用。
public class PhantomReferenceExample {
public static void main(String[] args) {
// 创建一个字符串对象,并将其放入虚引用中
String str = new String("这是一个虚引用示例");
ReferenceQueue<String> referenceQueue = new ReferenceQueue<>();
PhantomReference<String> phantomRef = new PhantomReference<>(str, referenceQueue);
// 清空强引用,使字符串对象只被虚引用引用
str = null;
// 从虚引用中获取对象
String retrieved = phantomRef.get();
// 获取虚引用的引用队列
PhantomReference<String> before = (PhantomReference<String>) referenceQueue.poll();
// 打印虚引用中的对象和引用队列
System.out.println("从虚引用中获取的对象:" + retrieved);
System.out.println("虚引用的引用队列:" + before);
// 模拟垃圾回收过程
System.gc();
// 等待一段时间以确保垃圾回收器完成回收
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
// 检查引用队列,查看是否有虚引用对象被放入队列中
PhantomReference<String> removedRef = (PhantomReference<String>) referenceQueue.poll();
if (removedRef != null) {
System.out.println("虚引用对象已被放入引用队列中");
System.out.println("虚引用的引用队列:" + removedRef);
} else {
System.out.println("虚引用对象未被放入引用队列中");
}
}
}
运行上面程序,结果如下
在这个示例中,我们首先创建一个字符串对象,并将其放入虚引用中。然后,我们清空了强引用,使字符串对象只能被虚引用引用。接下来,我们获取虚引用中的对象,获取虚引用的引用队列,并模拟垃圾回收过程。最后,我们检查引用队列,查看是否有虚引用对象被放入队列中。
运行示例代码后,你会看到虚引用对象不可用(retrieved为null),并且虚引用对象已经被垃圾回收器回收并放入引用队列中。这演示了虚引用的行为,可以用于执行某些操作,例如清理相关资源,当对象被回收时。