IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> 【JVM】JVM03(图解垃圾回收机制)上 -> 正文阅读

[Java知识库]【JVM】JVM03(图解垃圾回收机制)上

??写在前面


  • 这里是温文艾尔の学习之路
  • 👍如果对你有帮助,给博主一个免费的点赞以示鼓励把QAQ
  • 👋博客主页🎉 温文艾尔の学习小屋
  • ??更多文章👨?🎓请关注温文艾尔主页📝
  • 🍅文章发布日期:2021.12.29
  • 👋java学习之路!
  • 欢迎各位🔎点赞👍评论收藏??
  • 🎄新年快乐朋友们🎄
  • 👋jvm学习之路!

文章笔记参考黑马程序员


在这里插入图片描述

??1.如何判断对象可以回收

??1.1引用计数法

一个对象收到引用时计数+1,一个对象失去引用时计数-1,一个对象的引用计数为0时,该对象被当作垃圾进行回收
但是这样会有一个问题

循环引用
在这里插入图片描述
当A对象和B对象相互引用时,他们的引用计数都是1,但是他们却没有被其他对象所使用,这样因为他们的引用计数不能归0导致两个对象不能作为垃圾被回收,导致内存泄漏

??1.2可达性分析算法

此算法为java虚拟机采用的一种垃圾回收算法,首先要确定一个肯定不会被当成垃圾回收的对象GC Root(根对象)

  • java虚拟机中的垃圾回收器采用可达性分析来探索所有存活的对象
  • 扫描堆中的对象,看是否能够沿着GC Root对象为起点的引用链找到该对象,找不到,表示可以回收

可以作为GC Root的对象

  • 虚拟机栈(栈帧中的本地变量表)中引用的对象
  • 方法区中类静态变量引用的对象
  • 方法区中常量引用的对象
  • 本地方法栈中JNI(即一般说的Native方法)引用的对象

??2.五种引用

  1. 强引用
  2. 软引用
  3. 弱引用
  4. 虚引用
  5. 终结器引用

下面我们分别进行描述

??2.1强引用

在这里插入图片描述
我们平时所使用的引用便是强引用,比如我们new一个对象A,把这个对象通过等号(赋值运算符)赋值给一个变量m,那么就称这个变量m强引用了刚刚的对象A

强引用的特点:

只要沿着GC root的引用链能够找到该对象,他就不会被垃圾回收,就比如上图中的C对象能找到A1对象,那么A1对象就不能被回收,当B对象和C对象对A1对象的引用都断开时,A1对象才能被垃圾回收

??2.2 软引用

在这里插入图片描述
如图,A2对象使用过软引用对象被C对象间接引用到,只要满足垃圾回收时,并且回收完内存也不够时,那么软引用所引用的A2对象就会被释放掉

所以软引用引用对象被释放的条件是

  • 没有强引用对象引用它
  • 发生垃圾回收
  • 垃圾回收之后内存不够

软引用的应用案例

    public static void soft(){
        ArrayList<SoftReference<byte[]>> list = new ArrayList<>();
        for (int i = 0; i < 5; i++) {
            SoftReference<byte[]> ref = new SoftReference<>(new byte[_4MB]);
            System.out.println(ref.get());
            list.add(ref);
            System.out.println(list.size());
        }
        System.out.println("循环结束:"+list.size());
        for (SoftReference<byte[]> ref : list) {
            System.out.println(ref.get());
        }
    }
list先引用软引用对象,软引用对象间接的引用byte数组

list和SoftReference之间是强引用,SoftReferencebyte数组之间是软引用

内存充足的时候软引用引用的对象保留,但是当内存不足的时候,软引用引用的对象就会被清除

??2.3 弱引用

在这里插入图片描述
和软引用的区别是,当弱引用引用该对象时,发生垃圾回收不管内存是否充足,弱引用所引用的对象都会被回收

public class Demo03 {
    private static final int _4MB = 4*1024*1024;
    public static void main(String[] args) throws IOException {

        List<WeakReference<byte[]>> list = new ArrayList<>();
        
        for (int i = 0; i < 10; i++) {
            //关联了软引用对象和引用队列,当软引用所关联的byte[]被回收时,软引用自己会加入到引用队列queue中去
            WeakReference<byte[]> ref = new WeakReference<>(new byte[_4MB]);
            list.add(ref);
            for (WeakReference<byte[]> w: list){
                System.out.println(w.get()+"");
            }
            System.out.println();
        }
        System.out.println("循环结束:"+list.size());
    }
}

通过list集合引用WeakReference,通过WeakReference间接的引用byte[]数组,这样进行垃圾回收,就会尝试把WeakReference运用的byte数组所占用的内存做释放

??引用队列

在这里插入图片描述
当软引用所引用的对象或弱引用引用的对象被清除之后,软引用和弱引用本身并不会消失,软引用和弱引用本身也是一个对象,此时软引用和弱引用会进入引用队列

软引用和弱引用自身也要占用一定内存,如果想释放软引用和弱引用的内存,需要使用引用队列找到它们,对其做进一步的处理

引用队列操作代码

public class Demo02 {
    private static final int _4MB = 4*1024*1024;
    public static void main(String[] args) throws IOException {

        ArrayList<SoftReference<byte[]>> list = new ArrayList<>();

        //引用队列
        ReferenceQueue<byte[]> queue = new ReferenceQueue<>();


        for (int i = 0; i < 5; i++) {
            //关联了软引用对象和引用队列,当软引用所关联的byte[]被回收时,软引用自己会加入到引用队列queue中去
            SoftReference<byte[]> ref = new SoftReference<>(new byte[_4MB],queue);
            System.out.println(ref.get());
            list.add(ref);
            System.out.println(list.size());
        }

        Reference<? extends byte[]> poll = queue.poll();
        while (poll != null){
            list.remove(poll);
            poll = queue.poll();
        }

        for (SoftReference<byte[]> ref : list) {
            System.out.println(ref.get());
        }
    }
}

关联软引用对象和引用队列,当软引用所关联的byte[]被回收时,软引用自己会加入到引用队列queue中去,之后查看引用队列中是否有软引用,有就将其移出

??2.4虚引用

在这里插入图片描述
ByteBuffer被回收的时候,他分配的直接内存并不能被java的垃圾回收管理,所以我们将虚引用对象Cleaner进入引用队列,虚引用所在队列会有一个叫RefrenceHandlel的线程,来定时到这个引用队列中找新入队的Cleaner,如果有就调用Cleaner中的clean方法,根据记录的直接内存的地址调用Unsafe.freeMemary方法来清理直接内存

在这里插入图片描述

??2.5终结器引用

在这里插入图片描述
所有的java对象都继承自Object类,Object类有finallize()终结方法,当对象重写了终结方法并且没有强引用,他就可以被当成垃圾回收,终结方法的调用依靠终结器引用

在这里插入图片描述
如上图当A4对象被垃圾回收时,在A4对象被真正清除之前,终结期引用进入引用队列,再由一个优先级很低的线程(finallizeHandler)查看引用队列中的终结器引用,通过终结器引用找到将要垃圾回收的对象,调用对象的finallize方法,调用之后,该对象就可以被垃圾回收了

??2.6引用总结

在这里插入图片描述

??3.垃圾回收算法

??3.1标记清除

在这里插入图片描述
第一个阶段:标记
顺着GC Root查找没有引用的对象,将其进行标记

在这里插入图片描述
第二个阶段:清除
将垃圾对象所占用的空间释放
在这里插入图片描述

释放不意味着将每一个字节进行清理操作,清除只是把对象所占用内存的起始与结束地址记录下来,放在一个较空闲的地址链表里,下次分配内存的时候会直接覆盖这部分内存

标记清除算法的优点:

  • 速度快

标记清除算法的缺点:

  • 容易产生内存碎片,无法满足大对象的内存分配,造成内存溢出问题

??3.2标记整理

第一步:标记,和标记删除算法相同
在这里插入图片描述
顺着GC Root查找没有引用的对象,将其进行标记
第二步:整理
在这里插入图片描述
清除垃圾的过程中,它会把可用的对象向前移动,使内存更为紧凑,连续的空间更多

优点:

  • 没有内存碎片,空间连续

缺点

  • 整理的过程牵扯到对象的移动,效率就会变低

??3.3复制

在这里插入图片描述

将内存区域化成大小相等的两块区域,首先将没有被引用的对象进行标记,然后将from区存活的对象复制到to区,复制的过程中完成碎片的整理

在这里插入图片描述

复制完成后清空from区,并且交换from和to

在这里插入图片描述
优点

  • 不会产生碎片

缺点

  • 会占用双倍的内存空间

??4分代垃圾回收

在这里插入图片描述
在java中长时间使用的对象就会放在老年代当中(垃圾回收耗时较长。且频率低),用完就会丢弃的对象就会被放入新生代(垃圾回收比较频繁),这样可以针对对象生命周期的不同特点进行不同的垃圾回收策略

分代垃圾回收的流程

当我们创建一个新的对象时,新对象默认采用伊甸园的空间
在这里插入图片描述
当伊甸园中存放的对象达到上限,新产生的对象无处安放就会触发一次垃圾回收,我们称为Minor GC
在这里插入图片描述
随后沿GC Root引用链,标记未引用的对象,随后采用我们上面说到的复制算法,将存活的对象复制到幸存区To中,并使其寿命+1
在这里插入图片描述

回收伊甸园中的对象,随后交换幸存区From和幸存区To的位置
在这里插入图片描述
此后产生的新对象会再次放入伊甸园
在这里插入图片描述
当又经过了一段时间,伊甸园又满了,就会触发第二次垃圾回收,第二次垃圾回收除了要把伊甸园中存活的对象找到以外,还会寻找幸存区中继续存活的对象,第二次垃圾回收会把伊甸园中幸存的对象转移到幸存区To中

并且该对象寿命+1,原from幸存区中上一次存活的对象转移到to中,并且寿命+1

在这里插入图片描述
回收伊甸园和幸存区中剩余的的垃圾对象
在这里插入图片描述
交换幸存区From和幸存区To
在这里插入图片描述
随后产生的新对象就可以放入伊甸园
在这里插入图片描述
幸存区中的对象会有一个默认阈值,例如默认阈值为15次
在这里插入图片描述
一旦达到15次,且对象依然存活,我们就认为该对象价值较高,该对象就会晋升到老年代中
在这里插入图片描述
如果新生代和老年代内存都达到极限
在这里插入图片描述
会先触发一次minor gc,如果此后空间仍不足,会触发一次Full GC,从新生代到老年代都会做一次清理,清理回收新生代和老年代中所有无用对象

大对象处理策略

当向伊甸园内添加一个非常大的对象时,达到即使伊甸园为空也无法容纳该对象,那么这个对象将直接晋升至老年代

??4.1分代垃圾回收总结

- 对象首先分配在伊甸园区域
- 
- 伊甸园空间不足时,触发minor gc,伊甸园和from存活的对象使用copy复制到to中,存活的对象年龄+1,
  并且交换from,to
  
- minor gc会引发stop the world,暂停其他用户的线程,等垃圾回收结束,用户线程才恢复运行
- 
- 当对象寿命超过阈值时,会晋升至老年代,最大寿命是15次(4bit)
- 
- 当老年代空间不足,会先尝试触发minor gc,如果之后空间仍不足,那么触发full gc,STW的时间更长

在这里插入图片描述

  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2022-01-24 10:41:48  更:2022-01-24 10:41:52 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 9:26:58-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码