jvm来教教你怎么区分是不是垃圾

18 篇文章 0 订阅
3 篇文章 0 订阅

前言

没有对象的你每天都会new出一堆对象,按照以前的知识我们可以晓得这些new出的对象都是存放在堆中,而堆中总有一天是会被占满的,而且有些不会再用的对象还存放中堆中,当jvm对这些不会再使用的对象在清理时,就开始进行垃圾回收,接下来我们来聊聊怎么区分这个对象是不是垃圾

小知识

怎么判断一个对象是否可以回收

计数法

该对象被其他对象引用一次,该对象的计数器就会加1,如果对象的计数器为0时,该对象就可以被回收了。
弊端
如果两个对象互相引用,如下图所示
在这里插入图片描述
这个时候a对象引用了b对象,而b对象又引用了a,这时a被回收的条件就是b被回收,b也同样如此,就产生了类似死锁的情况,从而导致了内存的泄露。

可达性分析算法

这个是java中采用的回收机制
先了解一个概念
根对象(GC ROOT)
肯定不可以当作垃圾回收的对象,如果一个对象没有被根对象引用,就可以回收
可以作为根对象的对象类型:

  • 系统对象
  • 加锁的对象
  • 活动线程中的对象,局部对象所引用的对象可做gcroot,同时参数中对象也是可以作为gcroot对象
基本原理

扫描堆中的对象,看是否能够沿着GC Root对象为起点的引用链找到该对象,找不到,表示可以回收

几种引用

不同的引用,对应引用的对象的回收时机不同,接下来介绍一下这几种引用

强引用

例如new出来的就是强引用

特点

  • 只要沿着gc root链可以找到该对象,就无法被垃圾回收
  • 只要没有直接或则间接对其强引用之后就可以垃圾回收了

软引用

特点

  • 只要未被gc root直接引用,垃圾回收时就会自动回收,例从C到软引用再到A2,当然此时需要B不在引用A2时,就可以发生垃圾回收

应用场景

强引用下导致堆空间溢出

   /**
         * 强引用会导致堆空间不够用
         */
        int _1M=1024*1024;
        List<byte[]> list=new LinkedList<>();
       for(int i=0;i<5;i++){
           list.add(new byte[_1M*2]);
       }

软引用下

在这种方式下其实就是使用软引用进行嵌套强引用,也就是SoftReference嵌套byte数组,从而达到软引用的目的,这样一旦出现堆内存不够就会进行释放软引用对象

List<SoftReference<byte[]>> list=new LinkedList<>();
for (int i = 0; i <100 ; i++) {
    SoftReference softReference=new SoftReference(new byte[_1M*2]);
    list.add(softReference);
}

这个过程中一旦出现了堆空间不够,就会清理软引用对象引用的对象,但是此时软引用对象还在,虽然占据内存比较小,但最好还是清理一下

使用引用队列进行处理,下方代码,关联了软引用队列,软引用关联的对象回收时,软引用对象会加入队列中,从而实现回收

这里我个人的理解就是判断这些软引用有没有引用其他对象,如果没有,则将其在队列中删除,从而将队列对软引用对象的强引用解除掉,从而实现对象的回收

   /**
         * 关联了软引用队列,软引用关联的对象回收时,软引用对象会加入队列中,从而实现回收
         */
        ReferenceQueue<byte[]> referenceQueue=new ReferenceQueue<>();
        List<SoftReference<byte[]>> list=new LinkedList<>();
        for (int i = 0; i <10 ; i++) {
            SoftReference softReference=new SoftReference(new byte[_1M*2],referenceQueue);
            list.add(softReference);
        }
        Reference<? extends byte[]> poll = referenceQueue.poll();
        while(poll!=null){
            referenceQueue.remove();
            poll=referenceQueue.poll();
        }

弱引用

特点

  • 当没有强引用时,若内存不够会回收软引用的对象,无论够不够都会回收弱引用对象
  • 释放之后,因为软弱引用仍占用空间,因此需将二者放入引用队列中,进行循环依次释放空间

虚引用(必须配合引用队列)

例如Bytebuffer就是需要一个虚引用对象Cleaner,因为ByteBuffer若是在强引用引用结束之后,会对其进行回收,但是此时直接内存不由jvm管理,这就需要把虚引用对象放置在引用队列中,从而实现对直接内存的回收(虚引用对象就是Cleaner,来调用Unsafe的Free memory()来进行释放)

终结器引用(必须配合引用队列)

例如A对象重写了finalize(),并且A即将被垃圾回收,会调用finalize方法,将放置一个终结器引用到队列中,会有一个优先级很低的线程会来检查队列中有无需要释放的引用,从而实现对象的回收,这时可进行个人设置的方法,因此可以得出finalize()执行效率挺差的

总结

学习笔记,分段记录一下,如有错误希望大佬们可以在评论区指正,感谢感谢

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小王不头秃

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值