强引用、软引用、弱引用、虚引用有何区别Java里面,大家都知道垃圾回收,那你知道怎么让垃圾回收器回收不了你的东西吗?嘿嘿
Java里面,大家都知道垃圾回收,那你知道怎么让垃圾回收器回收不了你的东西吗?嘿嘿,要弄清楚这个问题,你就得搞明白什么是强引用、软引用、弱引用、虚引用;跟我一起来看看...
一、强引用
强引用(Strong Reference)是Java中最常见的引用类型,它是一个直接的引用,指向一个对象。当一个对象具有强引用时,它不会被垃圾回收器回收,即使系统内存不足。
1.1 定义和特点
-
定义:强引用是使用
new
关键字创建的对象引用。 -
特点:
-
只要强引用存在,垃圾回收器就不会回收被引用的对象。
-
强引用可能导致内存泄漏,因为即使不再需要对象,只要强引用还存在,对象就不会被回收。
-
1.2 强引用与垃圾回收的关系
-
当一个对象没有任何强引用指向它时,它将变成垃圾回收器的回收目标。
-
即使内存不足,只要对象还有强引用,垃圾回收器也不会回收它,这可能导致
OutOfMemoryError
。
1.3 强引用的使用
以下是一个简单的示例,展示如何使用强引用:
/**
* 在这里,`strongObject`是一个强引用,指向一个新创建的`Object`实例。
* 只要`strongObject`存在,即使我们调用了`System.gc()`,对象也不会被垃圾回收,因为它仍然有强引用指向它。
* 在实际应用中,我们应该在不再需要对象时,将引用设置为`null`,以便垃圾回收器可以回收该对象。
*/
public class StrongReferenceExample {
public static void main(String[] args) {
// 创建一个强引用对象
Object strongObject = new Object();
// 只要这个引用存在,对象不会被回收
System.out.println("Strong object created.");
// 假设这是一段代码,使用这个对象
useObject(strongObject);
// 即使不再使用这个对象,只要这个引用还存在,对象不会被回收
// 这里我们只是简单地打印出来,实际上应该在适当的时候释放引用
System.gc(); // 建议垃圾回收,但实际回收时机由JVM决定
}
private static void useObject(Object obj) {
// 对象被使用
System.out.println("Using the object.");
}
}
二、软引用
软引用(Soft Reference)是Java中提供的一种比较弱的引用类型,它允许垃圾回收器在内存不足时回收这些对象,即使还有强引用指向这些对象。
2.1 定义和特点
-
定义:软引用是通过
java.lang.ref.SoftReference
类实现的引用类型。 -
特点:
-
软引用被用来实现内存敏感的缓存。
-
当系统内存不足时,垃圾回收器会首先回收软引用指向的对象,即使它们还有强引用。
-
软引用可以与引用队列(
java.lang.ref.ReferenceQueue
)联合使用,当软引用所指向的对象被垃圾回收时,这个软引用会被加入到与之关联的引用队列中。
-
2.2 软引用的适用场景
-
软引用非常适用做缓存
-
软引用非常适合用于缓存数据,尤其是那些占用大量内存的数据对象。
-
当内存资源紧张时,缓存中的对象可以被回收,从而释放内存。
-
2.3 软引用与垃圾回收的关系
-
当系统内存充足时,软引用所指向的对象可以一直存活,不会被垃圾回收。
-
当系统内存不足时,垃圾回收器会考虑回收软引用所指向的对象,即使它们还有强引用。
-
软引用可以与引用队列一起使用,以便在软引用所指向的对象被回收时进行一些清理工作或重新加载数据。
使用软引用时,需要注意软引用本身是强引用,只有软引用所指向的对象可以被回收。如果软引用本身被回收,那么它所指向的对象也会丢失。
2.4 软引用的使用
以下是一个使用软引用实现的简单缓存机制示例:
import java.lang.ref.SoftReference;
public class SoftReferenceExample {
private Map<String, SoftReference<String>> cache = new HashMap<>();
public String getFromCache(String key) {
// 尝试从缓存中获取软引用对象
SoftReference<String> ref = cache.get(key);
if (ref != null) {
return ref.get(); // 获取软引用指向的对象
}
return null;
}
public void addToCache(String key, String value) {
// 将新对象以软引用的形式存入缓存
cache.put(key, new SoftReference<>(value));
}
public static void main(String[] args) {
SoftReferenceExample cacheExample = new SoftReferenceExample();
cacheExample.addToCache("key1", "This is a cached value.");
// 假设经过一段时间,内存不足
System.gc(); // 建议垃圾回收
// 尝试从缓存中获取值
String value = cacheExample.getFromCache("key1");
if (value != null) {
System.out.println("Value retrieved from cache: " + value);
} else {
System.out.println("Value has been garbage collected.");
}
}
}
三、弱引用
弱引用(Weak Reference)是Java中的一种引用类型,它允许垃圾回收器在任何时候回收其所指向的对象,即使对象仍然有弱引用。
3.1 定义和特点
-
定义:弱引用是通过
java.lang.ref.WeakReference
类实现的引用类型。 -
特点:
-
弱引用所指向的对象,如果没有任何强引用指向它,那么它将被垃圾回收器回收。
-
弱引用可以与引用队列(
java.lang.ref.ReferenceQueue
)联合使用,当弱引用所指向的对象被垃圾回收时,这个弱引用会被加入到与之关联的引用队列中。
-
3.2 弱引用的适用场景
-
映射表:当映射表中的某些条目不再被外部强引用时,使用弱引用可以避免内存泄漏。
-
事件监听器:事件监听器可能会意外地被保留在内存中,因为它们被内部类持有引用。使用弱引用可以确保监听器在不再需要时能够被回收。
3.3 弱引用与垃圾回收的关系
-
弱引用不会阻止垃圾回收器回收其所指向的对象,即使对象还有弱引用。
-
当垃圾回收器准备回收一个对象时,如果该对象只有弱引用,它会将这些弱引用加入到与之关联的引用队列中。
-
这允许开发者在对象被回收时执行一些清理工作,例如注销监听器或从映射表中删除条目。
使用弱引用时,需要注意弱引用本身是强引用,只有弱引用所指向的对象可以被回收。如果弱引用本身被回收,那么它所指向的对象也会丢失。
3.4 弱引用的使用
以下是一个使用弱引用的示例,展示如何将弱引用用于事件监听器:
import java.lang.ref.WeakReference;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
public class WeakReferenceExample {
public static void main(String[] args) {
// 创建一个鼠标事件监听器
MouseAdapter adapter = new MouseAdapter() {
public void mouseClicked(MouseEvent e) {
System.out.println("Mouse clicked at " + e.getX() + ", " + e.getY());
}
};
// 使用弱引用包装监听器
WeakReference<MouseAdapter> weakAdapter = new WeakReference<>(adapter);
// 假设这是某个组件,我们将其监听器设置为弱引用
Component component = new Component(); // 假设的组件类
component.addMouseListener(weakAdapter.get());
// 清除对监听器的强引用
adapter = null;
// 建议垃圾回收
System.gc();
// 检查监听器是否被回收
if (weakAdapter.get() == null) {
System.out.println("MouseListener has been garbage collected.");
} else {
System.out.println("MouseListener is still alive.");
}
}
}
四、虚引用
虚引用(Phantom Reference)是Java中四种引用类型中最弱的一种。它主要用来跟踪对象被垃圾回收的活动,并且必须与引用队列(ReferenceQueue
)联合使用。当垃圾回收器准备回收一个对象时,如果该对象还有虚引用,那么在回收对象的内存之前,这个虚引用会被加入到与之关联的引用队列中。
4.1 定义和特点
-
定义:虚引用通过
java.lang.ref.PhantomReference
类实现,它是所有引用中最弱的,即使存在虚引用,对象也可能被垃圾回收。 -
特点:
-
无法通过虚引用访问对象,
PhantomReference.get()
方法总是返回null
。 -
虚引用的主要目的是在对象被垃圾收集器回收时接收到系统通知。
-
4.2 虚引用的用途
虚引用常用于跟踪对象被垃圾回收的活动,例如,可以用来回收一些非Java内的资源,如直接内存(DirectByteBuffer)的释放。
4.3 虚引用与垃圾回收的关系
-
虚引用不会影响对象的回收时间,即使存在虚引用,对象也可能在任何时间被垃圾回收。
-
当对象被确定为可回收(没有强引用、软引用或弱引用),并且垃圾回收器准备回收该对象时,虚引用会被加入到引用队列中。
-
程序可以通过检查引用队列来确定对象是否已经被回收,并在对象回收前执行必要的操作,如资源清理。
请注意,虚引用的使用相对复杂,且在实际编程中较为少见,通常只在需要精细控制对象回收时使用。“慎用”
4.4 虚引用的使用
以下是一个简单的示例,展示如何使用虚引用和引用队列来跟踪对象的回收:
import java.lang.ref.PhantomReference;
import java.lang.ref.ReferenceQueue;
public class PhantomReferenceExample {
public static void main(String[] args) {
Object obj = new Object();
ReferenceQueue<Object> queue = new ReferenceQueue<>();
PhantomReference<Object> phantomRef = new PhantomReference<>(obj, queue);
// 清除非强引用并触发GC
obj = null;
System.gc();
// 轮询引用队列,检查虚引用是否已经被加入
while (true) {
PhantomReference<?> ref = (PhantomReference<?>) queue.poll();
if (ref != null) {
System.out.println("Object was reclaimed by GC.");
break;
}
}
}
}
五、四种引用的关系
5.1 引用强度
5.2 垃圾回收时机
5.3 用途
内存感知能力:软引用具有一定的内存感知能力,而弱引用和虚引用没有。
引用队列:软引用和弱引用可以与引用队列一起使用,虚引用必须与引用队列一起使用。
六、总结
Java中的四大引用类型:强引用、软引用、弱引用和虚引用,它们之间的主要区别在于它们对对象生命周期的影响以及垃圾回收器如何对待这些引用。
在实际开发中,我们大多数人都是使用的强引用;合理的使用软引用、弱引用和虚引用可以有效提升我们程序的性能,但是咱们一定要小心谨慎,因为这里面搞得不好就会出现天坑。
希望本文对您有所帮助。如果有任何错误或建议,请随时指正和提出。
同时,如果您觉得这篇文章有价值,请考虑点赞和收藏。这将激励我进一步改进和创作更多有用的内容。
感谢您的支持和理解!
转载自:https://juejin.cn/post/7403337327833169960