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

jvm来教教你怎么区分是不是垃圾,第1张

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

jvm来教教你怎么区分垃圾

前言小知识

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

计数法可达性分析算法

基本原理 几种引用

强引用软引用弱引用虚引用(必须配合引用队列)终结器引用(必须配合引用队列) 总结

前言

没有对象的你每天都会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 list=new linkedList<>();
       for(int i=0;i<5;i++){
           list.add(new byte[_1M*2]);
       }

软引用下

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

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

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

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

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

   
        ReferenceQueue referenceQueue=new ReferenceQueue<>();
        List> list=new linkedList<>();
        for (int i = 0; i <10 ; i++) {
            SoftReference softReference=new SoftReference(new byte[_1M*2],referenceQueue);
            list.add(softReference);
        }
        Reference poll = referenceQueue.poll();
        while(poll!=null){
            referenceQueue.remove();
            poll=referenceQueue.poll();
        }
弱引用

特点

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

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

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

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

总结

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

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/zaji/5712248.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-17
下一篇 2022-12-18

发表评论

登录后才能评论

评论列表(0条)

保存