Java 引用类型与内存管理实践
在 Java 内存管理中,引用类型的正确使用对于优化性能和避免内存泄漏至关重要。本文将详细介绍四种引用类型及其实际应用场景,并通过代码示例帮助理解。
1. 强引用(Strong Reference)
强引用是最常见的引用形式,通过 new 创建的对象都属于强引用。只要存在强引用,对象就不会被垃圾回收器(GC)回收。
Object strongObj = new Object(); // 强引用
strongObj = null; // 设置为 null 后,对象可被 GC 回收
2. 软引用(Soft Reference)
软引用通过 SoftReference 类实现。当内存不足时,GC 会优先回收软引用对象,因此它常用于缓存场景。
// 创建软引用
SoftReference<String> softRef = new SoftReference<>(new String("Soft"));
// 获取对象
String value = softRef.get();
System.out.println(value); // 输出: Soft
// 手动触发 GC(内存充足时可能不会回收)
System.gc();
value = softRef.get();
System.out.println(value == null ? "已回收" : "未回收"); // 取决于内存情况
3. 弱引用(Weak Reference)
弱引用通过 WeakReference 实现。无论内存是否充足,只要 GC 检测到弱引用对象,就会立即回收它,适用于临时关联的场景。
// 创建弱引用
WeakReference<String> weakRef = new WeakReference<>(new String("Weak"));
// 获取对象
String data = weakRef.get();
System.out.println(data); // 输出: Weak
// 手动触发 GC(弱引用对象会被立即回收)
System.gc();
data = weakRef.get();
System.out.println(data == null ? "已回收" : "未回收"); // 输出: 已回收
4. 虚引用(Phantom Reference)
虚引用通过 PhantomReference 实现,无法直接访问对象,主要用于在对象被回收时接收通知,通常需要配合引用队列使用。
// 创建引用队列
ReferenceQueue<String> queue = new ReferenceQueue<>();
// 创建虚引用
PhantomReference<String> phantomRef = new PhantomReference<>(new String("Phantom"), queue);
// 虚引用无法获取对象
System.out.println(phantomRef.get()); // 输出: null
// 手动触发 GC 并等待回收完成
System.gc();
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
// 检查引用队列
if (queue.poll() != null) {
System.out.println("对象已被回收");
}
Spring Boot 中的应用
在 Spring Boot 中,ConcurrentReferenceHashMap 是一个常用工具类,支持软引用和弱引用,默认使用软引用实现缓存功能。以下是该类的核心初始化逻辑:
public ConcurrentReferenceHashMap(
int initialCapacity, float loadFactor, int concurrencyLevel, ReferenceType referenceType) {
Assert.isTrue(initialCapacity >= 0, "Initial capacity must not be negative");
Assert.isTrue(loadFactor > 0f, "Load factor must be positive");
Assert.isTrue(concurrencyLevel > 0, "Concurrency level must be positive");
Assert.notNull(referenceType, "Reference type must not be null");
this.loadFactor = loadFactor;
this.shift = calculateShift(concurrencyLevel, MAXIMUM_CONCURRENCY_LEVEL);
int size = 1 << this.shift;
this.referenceType = referenceType;
int roundedUpSegmentCapacity = (int) ((initialCapacity + size - 1L) / size);
int initialSize = 1 << calculateShift(roundedUpSegmentCapacity, MAXIMUM_SEGMENT_SIZE);
Segment[] segments = (Segment[]) Array.newInstance(Segment.class, size);
}
通过上述代码可以看出,Spring 利用引用类型实现了高效的缓存机制,同时确保了内存使用的安全性。