百日筑基第三十四天-JAVA中的强/软/弱/虚引用

百日筑基第三十四天-JAVA中的强/软/弱/虚引用

Java对象的引用被划分为4种级别,分别为强引用软引用弱引用以及虚引用。帮助程序更加灵活地控制对象的生命周期和JVM进行垃圾回收

强引用

强引用是最普遍的引用,一般把一个对象赋给一个引用变量,这个引用变量就是强引用。这个引用保存在Java栈中,而真正的引用内容保存在Java堆中。

//  强引用
Object obj=new Object();

如果使用了强引用,垃圾回收器GC时不会回收该对象,**当空间不足时,JVM宁愿抛出OutOfMemoryError异常。**因为JVM认为强引用的对象是用户正在使用的对象,它无法分辨出到底该回收哪个,强行回收有可能导致系统严重错误。如果想GC时回收该对象,让其超出对象的生命周期范围或者设置引用指向null,并且会执行对象的`finalize 函数。如下:帮助垃圾回收期回收此对象,具体什么时候收集这要取决于GC算法。

obj = null;

举个例子: StrongRefenenceDemo中尽管o1已经被回收,但是o2强引用 o1,一直存在,所以不会被GC回收。

public class StrongRefenenceDemo {

    public static void main(String[] args) {
        Object o1 = new Object();
        Object o2 = o1;
        o1 = null;
        System.gc(); // 其实就算我们显示调用,GC 也可能不会立即执行
        System.out.println(o1);  //null
        System.out.println(o2);  //java.lang.Object@4534fdg7
    }
}

软引用

对象处在有用但非必须的状态,只有当内存空间不足时,GC会回收该引用对象的内存。可以用来实现高速缓存,比如网页缓存、图片缓存等。需要通过SoftReference类来实现。

// 注意:sr引用也是强引用,它是指向SoftReference这个对象的,
// 这里的软引用指的是指向new String("str")的引用,也就是SoftReference类中T
SoftReference<String> sr = new SoftReference<String>(new String("str"));

软引用可以和一个引用队列ReferenceQueue联合使用,如果软引用所引用对象被垃圾回收,Java虚拟机就会把这个软引用加入到与之关联的引用队列中。

ReferenceQueue<Object> queue = new ReferenceQueue<>();
Object obj = new Object();
SoftReference softRef = new SoftReference<Object>(obj,queue);//删除强引用
obj = null;//调用gc
System.gc();
System.out.println("gc之后的值: " + softRef.get()); // 对象依然存在
//申请较大内存使内存空间使用率达到阈值,强迫gc
byte[] bytes = new byte[100 * 1024 * 1024];//如果obj被回收,则软引用会进入引用队列
Reference<?> reference = queue.remove();
if (reference != null){
    System.out.println("对象已被回收: "+ reference.get());  // 

案例一: SpringBoot源码中大量使用ConcurrentReferenceHashMap合理的使用内存,间接的优化JVM,提高垃圾回收效率。

public class ConcurrentReferenceHashMap<K, V> extends AbstractMap<K, V> implements ConcurrentMap<K, V> {
    private static final ConcurrentReferenceHashMap.ReferenceType DEFAULT_REFERENCE_TYPE;
    static {
        DEFAULT_REFERENCE_TYPE = ConcurrentReferenceHashMap.ReferenceType.SOFT;
    }
    ......
}

SpringFactoriesLoad源码:Springboot SPI机制的主角

public final class SpringFactoriesLoader {
    private static final Map<ClassLoader, MultiValueMap<String, String>> cache = new ConcurrentReferenceHashMap();
    ......
    private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {
        MultiValueMap<String, String> result = (MultiValueMap)cache.get(classLoader);
        if (result != null) {
            return result;
        } else {
            try {
                Enumeration<URL> urls = classLoader != null ? classLoader.getResources("META-INF/spring.factories") : ClassLoader.getSystemResources("META-INF/spring.factories");
                LinkedMultiValueMap result = new LinkedMultiValueMap();

                while(urls.hasMoreElements()) {
                   ......
                }

                cache.put(classLoader, result);
                return result;
            } catch (IOException var13) {
                throw new IllegalArgumentException("Unable to load factories from location [META-INF/spring.factories]", var13);
            }
        }
    }

AnnotationsScanner自动配置过程中的注解扫描

abstract class AnnotationsScanner {
    private static final Map<AnnotatedElement, Annotation[]> declaredAnnotationCache = new ConcurrentReferenceHashMap(256);
    private static final Map<Class<?>, Method[]> baseTypeMethodsCache = new ConcurrentReferenceHashMap(256);

ThreadPoolTaskExecutor 异步任务线程池

public class ThreadPoolTaskExecutor extends ExecutorConfigurationSupport implements AsyncListenableTaskExecutor, SchedulingTaskExecutor {
    public ThreadPoolTaskExecutor() {
        this.decoratedTaskMap = new ConcurrentReferenceHashMap(16, ReferenceType.WEAK);
    }

案例二: Mybatis缓存类SoftCache用到的软引用:

public Object getObject(Object key) {
    Object result = null;
    SoftReference<Object> softReference = (SoftReference)this.delegate.getObject(key);
    if (softReference != null) {
        result = softReference.get();
        if (result == null) {
            this.delegate.removeObject(key);
        } else {
            synchronized(this.hardLinksToAvoidGarbageCollection) {
                this.hardLinksToAvoidGarbageCollection.addFirst(result);
                if (this.hardLinksToAvoidGarbageCollection.size() > this.numberOfHardLinks) {
                    this.hardLinksToAvoidGarbageCollection.removeLast();
                }
            }
        }
    }
    return result;}

弱引用

弱引用就是只要JVM垃圾回收器发现了它,不管内存是否足够,都会被回收。

Object object= new Object();
WeakReference<Object> weakReference= new WeakReference<>(object);
Object result = weakReference.get();

案例: WeakHashMapkey只有弱引用时,GC发现后会自动清理键和值,作为简单的缓存表解决方案。

public class WeakHashMapDemo {

    public static void main(String[] args) throws InterruptedException {
        myHashMap();
        myWeakHashMap();
    }

    public static void myHashMap() {
        HashMap<String, String> map = new HashMap<String, String>();
        String key = new String("k1");
        String value = "v1";
        map.put(key, value);
        System.out.println(map);

        key = null;
        System.gc();

        System.out.println(map);
    }

    public static void myWeakHashMap() throws InterruptedException {
        WeakHashMap<String, String> map = new WeakHashMap<String, String>();
        String key = new String("weak");
        String value = "map";
        map.put(key, value);
        System.out.println(map);
        //去掉强引用
        key = null;
        System.gc();
        Thread.sleep(1000);
        System.out.println(map);
    }
}

ThreadLocal: ThreadLocal.ThreadLocalMap.Entry继承了弱引用,key为当前线程实例,和WeakHashMap基本相同。

static class ThreadLocalMap {

    static class Entry extends WeakReference<ThreadLocal<?>> {
        Object value;

        Entry(ThreadLocal<?> k, Object v) {
            super(k);
            value = v;
        }
    }
    //......}

虚引用

虚引用和没有引用是一样的,需要和队列ReferenceQueue联合使用。**当jvm扫描到虚引用的对象时,会先将此对象放入关联的队列中,因此我们可以通过判断队列中是否存这个对象,来进行回收前的一些处理。**有哨兵的作用。

Object object= new Object();
ReferenceQueue queue = new ReferenceQueue();
PhantomReference pr = new PhantomReference(object, queue);
  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值