Java中的引用类型——强软弱虚

强引用

  • 没有任何引用指向这个对象,垃圾回收器(gc)就把他回收。
    在这里插入图片描述

软引用

在这里插入图片描述
运行结果:
在这里插入图片描述

  • 在上述代码中,SoftReference是一个软引用,里面new了一个字节数组。
  • SoftReference表示对字节数组的引用是一个软引用
  • 使用m.get()获得字节数组的内容。
  • 堆内存最大20M,当分配的字节数组超过20M,之前的软引用的字节数组对象就会被回收。(上述代码中,刚才开始分配一个软引用的字节数组10M,后来分配一个15M的字节数组,超过20M就会把软引用的对象回收)
    在这里插入图片描述

弱引用

  • 垃圾回收器看到就会回收。
    在这里插入图片描述
    运行结果
    在这里插入图片描述
弱引用的应用:ThreadLocal
  • 首先我们去读ThreadLocal的set()方法的源码:
    在这里插入图片描述
    我们可以看到它是将当前的ThreadLocal作为key放入一个map中。map是当前线程对象的。
  • 然后我们看getMap()方法:
    在这里插入图片描述
    每一个线程对象都有一个叫做threadLocals的map。
  • 跳转到threadLocals

在这里插入图片描述
threadLocals中放的就是和当前线程相关的ThreadLocal类型。
下面我们来梳理一下整个set过程:new一个Thread对象,里面的成员变量指向一个map,new一个ThreadLocal对象,调用它的set()方法,就会把这个ThreadLocal对象作为key,set的对象作为value放到当前线程里。
在这里插入图片描述

  • 下面我们继续读map的set()方法
    在这里插入图片描述
    在这里插入图片描述

  • 继续看Entry的源码:
    在这里插入图片描述
    map的一行看作一个entry,entry是一个WeakReference对象,当前的k(ThreadLocal)是被一个弱引用指向的。
    那么问题来了,为什么ThreadLocal是被弱引用指向的?
    在这里插入图片描述
    在这里插入图片描述
    如上图,当我们不需要tl的时候,tl和ThreadLocal的直接联系就没有了,但是由于ThreadLocal是存在map的key中,所以通过map,tl和ThreadLocal还有联系。如果在map中ThreadLocal是强引用,gc将不能将这个ThreadLocal回收,会产生内存泄漏。但如果在map中ThreadLocal是弱引用,当tl和ThreadLocal关系断开时,gc可以将ThreadLocal回收,就不会产生内存泄漏。
    面试题:ThreadLocal是怎么解决内存泄漏问题的:使用弱引用。

注意:当ThreadLocal被回收之后,map中的记录变成key=null,这条记录就没有用了,要使用remove()方法将这条记录删掉,否则还会产生内存泄露。

虚引用

  • 永远都get不到。在这里插入图片描述
    在这里插入图片描述
    监控堆外内存的垃圾回收线程:
    在这里插入图片描述
    运行结果:
    在这里插入图片描述
  • 应用:NIO用其实现
  • 作用:管理堆外内存
    在这里插入图片描述
    当我们有一个DirectByteBuffer对象,但它分配的内存空间是在JVM堆的外面,是操作系统的内存。如果DirectByteBuffer在JVM中没有任何引用指向它,就要对其进行回收。但如果直接将其从JVM中删除,那与之关联的堆外内存就失去联系,发生内存泄漏。因此堆外内存也要同时回收。所以JVM对这种对象,都为其进行虚引用,当对象被回收时会将其放在一个队列中,GC只需要监控这个队列,当有对象进入这个队列,就清理和这个对象相关的堆外内存。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值