在 java 中,引用类型决定了对象在垃圾回收时的生命周期。以 user 对象为例,分别演示强引用、软引用、弱引用、虚引用的用法及回收特性。
1. 强引用(strong reference)
特点:最常用的引用,只要强引用存在,对象永远不会被 gc 回收。
user user = new user("alice");
// 此时 user 是强引用,user 对象不会被回收
user = null; // 切断引用后,对象才可能被回收2. 软引用(softreference)
特点:通过 softreference 实现,当内存充足时保留,仅在内存即将耗尽(即将 oom)时才会被回收。适合实现内存敏感的高速缓存。
// 创建软引用
softreference<user> softref = new softreference<>(new user("bob"));
// 获取对象
user user = softref.get(); // 内存充足时返回 user 对象,oom 前可能返回 null
// 模拟内存紧张时,gc 会回收软引用指向的对象
system.gc(); // 不保证立即回收,但若内存紧张则会回收3. 弱引用(weakreference)
特点:通过 weakreference 实现,只要发生 gc,无论内存是否充足,对象都会被回收。常用于规范映射(如 weakhashmap)以及 threadlocal 的 key 设计。
// 创建弱引用
weakreference<user> weakref = new weakreference<>(new user("charlie"));
// 获取对象(可能为 null)
user user = weakref.get(); // gc 前存在,gc 后为 null
// 手动触发 gc,对象会被回收
system.gc();
system.out.println(weakref.get()); // 输出 null弱引用对象的回收时机是:只要垃圾回收器运行,且对象仅被弱引用所引用,该对象就会被回收。具体到 threadlocal:
线程中定义了一个 threadlocal 变量:
threadlocal<string> local = new threadlocal<>();- 此时
local变量持有对 threadlocal 实例的强引用(在栈上)。 - threadlocal 实例也被当前线程的
threadlocalmap中的 entry 弱引用着。
- 此时
当方法执行完毕,
local变量出栈,强引用消失。- threadlocal 实例现在只被 entry 弱引用。
随后发生垃圾回收(如内存不足时触发的 full gc 或系统调用的
system.gc())。- gc 发现 threadlocal 实例只有弱引用,将其回收。
- entry 的 key 字段(即弱引用本身)被清除,变为
null。
4. 虚引用(phantomreference)
特点:最弱的引用,通过 phantomreference 实现。无法通过 get() 获取对象实例,仅用于跟踪对象被回收的通知(必须配合 referencequeue)。常用于资源释放监控或对象回收前的清理。
// 必须配合引用队列
referencequeue<user> queue = new referencequeue<>();
// 创建虚引用
phantomreference<user> phantomref = new phantomreference<>(new user("david"), queue);
// 无法获取对象
user user = phantomref.get(); // 永远返回 null
// 当虚引用指向的对象被回收后,该引用会被加入队列
system.gc();
reference<? extends user> ref = queue.poll();
if (ref != null) {
// 执行回收后的清理工作
system.out.println("user 对象已被回收");
}5. 总结对比(以 user 对象为例)
| 引用类型 | 示例代码 | 回收时机 | 典型用途 |
|---|---|---|---|
| 强引用 | user u = new user(); | 永不回收(除非引用置空) | 普通对象 |
| 软引用 | softreference<user> s = new softreference<>(new user()); | 内存不足时回收 | 缓存(如图片缓存) |
| 弱引用 | weakreference<user> w = new weakreference<>(new user()); | 每次 gc 都可能回收 | weakhashmap、threadlocal 的 key |
| 虚引用 | phantomreference<user> p = new phantomreference<>(new user(), queue); | 任何时候都可能回收,且 get() 返回 null | 对象回收跟踪、资源释放 |
6. 延伸:threadlocal 为什么用弱引用?
threadlocal 内部 threadlocalmap 的 key 使用弱引用,目的是当 threadlocal 实例不再被外部强引用时,gc 可以回收它,避免 threadlocal 对象本身的内存泄漏。但 value 仍是强引用,所以仍需要手动调用 remove() 清除 value,防止线程池场景下出现内存泄漏。
// threadlocalmap.entry 源码简写
static class entry extends weakreference<threadlocal<?>> {
object value;
entry(threadlocal<?> k, object v) {
super(k); // key 是弱引用
value = v; // value 是强引用
}
}到此这篇关于java强引用、软引用、弱引用、虚引用的使用小结的文章就介绍到这了,更多相关java强引用、软引用、弱引用、虚引用内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!
发表评论