深入解析Java四大引用类型:从强引用到虚引用的内存管理艺术

在这里插入图片描述

1. 强引用(Strong Reference)

基本概念

强引用是Java中最常见的引用类型,也是默认的引用方式

// 强引用示例
public class StrongReferenceExample {
    public static void main(String[] args) {
        Object strongRef = new Object(); // 强引用
        
        // 手动解除引用
        strongRef = null; // 现在可以被GC回收
    }
}

特点

  • 只要强引用存在,垃圾回收器就永远不会回收被引用的对象
  • 即使内存不足时,JVM宁愿抛出OutOfMemoryError也不会回收强引用对象

使用场景

  • 日常开发中绝大多数对象的引用
  • 需要长期存在的对象

注意事项

  • 注意避免内存泄漏:当不再需要对象时,应及时将引用置为null
  • 集合类中的对象要注意及时清理

2. 软引用(Soft Reference)

软引用(SoftReference) 是一种比弱引用更“温和”的引用类型,它会在内存不足时(OOM前) 被垃圾回收器(GC)回收,而不是像弱引用那样立即回收。软引用非常适合用于实现内存敏感的缓存(例如图片缓存、临时数据缓存等)。

基本概念

软引用通过java.lang.ref.SoftReference类实现。

import java.lang.ref.SoftReference;

public class SoftReferenceExample {
    public static void main(String[] args) {
        SoftReference<byte[]> softRef = new SoftReference<>(new byte[1024 * 1024]); // 1MB缓存
        
        // 使用前检查
        byte[] cache = softRef.get();
        if (cache != null) {
            System.out.println("从缓存读取数据");
        } else {
            System.out.println("缓存已被回收,重新创建");
            cache = new byte[1024 * 1024];
            softRef = new SoftReference<>(cache);
        }
    }
}

特点

  • 当内存不足时,垃圾回收器会回收软引用指向的对象
  • 在内存充足时,软引用对象不会被回收

使用场景

  • 实现内存敏感的缓存(如配置、资源缓存)
  • 适合缓存那些可以重建但重建成本较高的对象

注意事项

  • 不要过度依赖软引用作为唯一的数据存储方式
  • 获取对象时需要检查是否为null(可能已被回收)
  • 在Android开发中,软引用的行为可能有差异

结合 ReferenceQueue 监控回收

软引用可以和 ReferenceQueue 结合使用,以便在对象被回收时得到通知。

import java.lang.ref.SoftReference
import java.lang.ref.ReferenceQueue

fun main() {
    val referenceQueue = ReferenceQueue<Hero>()

    // 创建软引用并关联到队列
    val softHero = SoftReference(Hero("Lancelot", 200), referenceQueue)

    // 模拟内存不足(分配大量对象)
    val list = mutableListOf<ByteArray>()
    repeat(100) {
        list.add(ByteArray(1024 * 1024)) // 每次分配1MB
        println("Memory pressure... SoftRef: ${softHero.get() ?: "NULL"}")
        Thread.sleep(50)
    }

    // 检查队列是否有被回收的软引用
    val recycledRef = referenceQueue.poll() as? SoftReference<Hero>
    if (recycledRef != null) {
        println("软引用已被回收") // 输出: 软引用已被回收
    }
}


3. 弱引用(Weak Reference)

基本概念

弱引用通过java.lang.ref.WeakReference类实现。

import java.lang.ref.WeakReference;
import java.util.WeakHashMap;

public class WeakReferenceExample {
    public static void main(String[] args) {
        // 弱引用示例
        WeakReference<Object> weakRef = new WeakReference<>(new Object());
        
        // WeakHashMap使用示例
        WeakHashMap<Object, String> weakMap = new WeakHashMap<>();
        Object key = new Object();
        weakMap.put(key, "临时数据");
        
        key = null; // 移除强引用
        System.gc(); // 触发GC后weakMap会自动清理
    }
}

特点

  • 无论内存是否充足,只要发生GC,弱引用对象就会被回收
  • 比软引用具有更短的生命周期

在这里插入图片描述

使用场景

  • 实现不会阻止对象被回收的监听器/观察者模式
  • 用于构建规范映射(如WeakHashMap)
  • 适用于临时性的、可随时重建的对象引用

注意事项

  • 获取对象前必须检查是否为null
  • 不适合用于必须长期存在的对象

4. 虚引用(Phantom Reference)

基本概念

虚引用通过java.lang.ref.PhantomReference类实现,必须与ReferenceQueue配合使用。

import java.lang.ref.PhantomReference;
import java.lang.ref.ReferenceQueue;

public class PhantomReferenceExample {
    public static void main(String[] args) {
        ReferenceQueue<Object> queue = new ReferenceQueue<>();
        Object resource = new Object();
        
        PhantomReference<Object> phantomRef = new PhantomReference<>(resource, queue);
        
        resource = null; // 释放强引用
        
        // 监控回收队列的线程
        new Thread(() -> {
            try {
                System.out.println("等待虚引用被回收...");
                queue.remove(); // 阻塞直到有引用入队
                System.out.println("检测到资源被回收,执行清理操作");
                // 这里可以执行native资源释放等操作
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        }).start();
        
        System.gc(); // 触发GC
    }
}

特点

  • 最弱的引用类型,无法通过虚引用获取对象实例
  • 对象被回收时,虚引用会被放入关联的ReferenceQueue
  • 主要用于跟踪对象被垃圾回收的活动

使用场景

  • 精细化的资源清理(如native资源释放)
  • 对象生命周期跟踪和监控
  • 实现比finalize更可靠的清理机制

注意事项

  • 不能用于常规的对象引用
  • 需要配合ReferenceQueue使用
  • 主要用于特殊的内存管理场景

引用类型对比

引用类型回收时机是否可通过get()获取典型用途
强引用永不自动回收常规对象引用
软引用内存不足时内存敏感缓存
弱引用GC运行时临时映射/监听器
虚引用GC运行时资源回收跟踪

实际应用建议

缓存实现

// 基于软引用的缓存实现
public class SoftCache<K, V> {
    private final Map<K, SoftReference<V>> cache = new HashMap<>();
    
    public void put(K key, V value) {
        cache.put(key, new SoftReference<>(value));
    }
    
    public V get(K key) {
        SoftReference<V> ref = cache.get(key);
        return ref != null ? ref.get() : null;
    }
}

资源清理模式

// 使用虚引用管理native资源
public class NativeResourceHolder {
    private final ReferenceQueue<Object> queue = new ReferenceQueue<>();
    private final Set<PhantomReference<Object>> refs = Collections.newSetFromMap(new WeakHashMap<>());
    
    public void registerResource(Object resource, Runnable cleanupTask) {
        refs.add(new PhantomReference<>(resource, queue) {
            @Override
            public void clear() {
                cleanupTask.run();
                super.clear();
            }
        });
    }
}


内存泄漏检测

// 弱引用+ReferenceQueue检测泄漏
public class LeakDetector {
    private final ReferenceQueue<Object> queue = new ReferenceQueue<>();
    private final Map<String, WeakReference<Object>> refs = new HashMap<>();
    
    public void register(Object obj, String id) {
        refs.put(id, new WeakReference<>(obj, queue));
    }
    
    public void checkLeaks() {
        Reference<?> ref;
        while ((ref = queue.poll()) != null) {
            // 找出泄漏的key
            refs.entrySet().removeIf(entry -> entry.getValue() == ref);
        }
    }
}

总结

  • 使用软引用缓存玩家常用数据
  • 使用弱引用管理事件监听器
  • 避免在核心服务中使用弱/软引用
  • 内存敏感场景

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值