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知识库 -> 深入理解Java垃圾回收机制-GC -> 正文阅读

[Java知识库]深入理解Java垃圾回收机制-GC

一、什么样的对象会被回收

GC在回收时并不会将所有对象全部回收,它会先判断该对象是否达到回收的标准,这个标准也很简单,就是看该对象是否有被其他对象引用,如果没有被引用则说明是垃圾,那各位小伙伴就有疑问了,GC是如何判断一个对象是否有被引用的呢?接下来博主就来给大家介绍一下相关的判断算法;

二、判定算法-引用计数算法

引用计数算法听名字就知道是通过计算对象的引用数量来判断是否可以被回收,每个对象都有自己的引用计数器,当被引用时就会+1,完成引用-1,所以当引用数量为0时,则会被判断为垃圾;

优点:执行效率高,程序执行受影响较小;
缺点:无法检测出循环引用的情况,导致内存泄露;

三、判定算法-可达性分析算法

官方解释:通过判断对象的引用链是否可以达来决定对象是否可以被回收;

通俗解释:如下图所示,从GC Root开始去查找引用的对象,找到之后将对象标记为可达,之后在查找子对象引用的对象(孙对象),以此类推,一直找下去,最后没有被标记的对象说明没有被引用,就是垃圾对象,就会别GC回收,那什么对象可以作为GC Root呢?分别是以下五种:

1.虚拟机栈中引用的对象(栈帧中的本地变量表)
2.方法区中的常量引用的对象
3.方法区中的类静态属性引用的对象
4.本地方法栈中JNI(Native方法)的引用对象
5.活跃线程的引用对象

在这里插入图片描述

**

了解了GC是如何查找,接下来咱们要开始重头戏,回收了;

**

四、标记-清除算法(Mark and Sweep)

根据名称就能知道,该算法一共两步,首先标记,然后清除;

标记:从根集合进行扫描,对存活的对象进行标记(可达性算法)
清除:对堆内存从头到尾进行线性遍历,回收不可达对象内存

下图可以很清晰的描述出该算法是如何进行垃圾回收的,在Mark阶段先标记出可达对象(绿色),之后在Sweep阶段直接将不可达对象(白色)回收,这样其实有一个不好的地方就是会产生大量的空间碎片,如图在Sweep后,最大相连的碎片块为2个,如果此时一个对象需要占用2个以上的碎片块时,就会再次触发GC回收,如果还没有足够的碎片块满足这个新的对象,那么就会抛出OutOfMemoryException;

在这里插入图片描述

五、复制算法(Copying)

将内存分为对象面和空闲面,创建对象时在对象面上操作,进行垃圾回收时会只需要将对象面上存活的对象复制到空闲面上,然后将对象面内的所有对象内存清楚即可;

下图为复制算法回收机制的回收前后内存对比,从图中可以知道以下几点:

1.解决了标记-清楚算法的碎片化问题
2.顺序分配内存,简单高效
3.只适用于对象存活率的场景,比如年轻代,因为如果对象存活率高,就需要复制大量的对象内存到空闲面上,则效率会大打折扣;
在这里插入图片描述

六、标记-整理算法(Compacting)

标记-整理算法和标记-清楚算法的第一步是一致的,都是使用可达性算法标记出存活的对象,第二步就不同了,标记-整理算法会移动所有的存活对象,然后按照内存地址次序依次排列,然后将末端内存地址以后的内存全部回收;

下图就是回收前和回收后的对比,该算法有以下几点好处:
1.避免了内存的不连续行,解决碎片化问题
2.不用设置两块内存去进行互换
3.适用于存活率高的场景,比如老年代
在这里插入图片描述

七、分代收集算法(Generational Collector)

分代其实是一种垃圾回收算法的组合拳,也就是按照不同的区域而去采用不同的辣鸡回收算法,比如复制算法适用于年轻代,而标记整理或标记清楚算法适用于老年代,目的就是为了提高JVM的回收效率,毕竟适合的才是最好的;

八、GC的分类

Minor GC
Minor GC是发生在年轻代垃圾回收动作,采用复制算法;

年轻代有两部分区域:
Eden区:所有的新创建的对象都放置在次,中文名伊甸园,人类出生的地方;
两个Survivor区:分为一个from,一个to,当Eden去满时就会将新创建的对象放置在这两个Survivor区中的其中一个上;

下图为新生代(也叫年轻代)和老年代的分布图,因为java对象很多都是早上创建好,下午就死了,存活率都很低,所以Eden区的内存稍微大些,老年代放置的都是年龄较大的不容易被回收的对象,所以占用的空间也比新生代大;
在这里插入图片描述
当Eden区满时会触发Minor GC,会将Eden区中存活的对象复制到Survivor区中的其中一个假设放置到Survivor A去了,然后会将Eden区清空,等到下一次Eden区又满了,又会触发Minor GC,这时候会将Eden区和Survivor A中存活的对象都放置到Survivor B中,然后将Eden区和Survivor A都清空,这也是为什么Survivor区中的from和to不是一成不变的原因,有时候你是from,有时候你是to;

对象如何晋升到老年代?
1.经历一定Minor GC次数依然存活的对象,因为每次Minor GC后都会将存活的对象年龄+1,但年龄达到15时就会被放置在老年代中,这个值可以设置,默认是15,不满意的话可以通过-XX:MaxTenuringThreshold来设置;
2.Survivor区中存放不下时,会放置在老年代中;
3.新生成的对象过大时,就不放在Eden中了,就会放置在老年代中(谁让你这么大),可以通过-XX:+PrerenuerSizeThreshold来设置;

Full GC
Full GC是发生在老年代垃圾回收动作,采用标记-清除或者标记-整理算法,Full GC的效率比Minor GC效率慢,大概慢10倍左右,但是Full GC触发的频率比Minor GC少;

触发Full GC的条件
1.老年代空间不足;
2.永久代空间不足(在jdk8及以后就删除了永久代,所以jdk8及以后的版本该条件不成立);
3.CMS GC时出现promotion failed,concurrent mode failure
promotion failed:在Minor GC时年轻代放不下了,只能放在老年代,而老年代也放不下了,就会触发;
concurrent mode failure:执行CMS GC时同时有对象要放置到老年代中,而老年代空间不足;
4.Minor GC晋升到老年代的平均大小大于老年代的剩余空间,比如第一次晋升了6M的对象,下一次晋升时会判断老年代的剩余空间是否大于6M,如果小于,则触发;
5.调用System.gc()(并不一定会触发,该方法只是起到提醒的作用,决定权在JVM手上);
6.使用RMI(远程)来进行RPC或管理的JDK应用,每小时执行1次Full GC;

Stop-the-World
JVM由于要执行GC而停止了应用程序的执行,并且这种情况会在任何一种GC算法中发生,当Stop-the-World发生时,除了GC所需要的线程以外,所有的线程都会处于等待状态,所以多数的GC优化都是通过减少Stop-the-World发生的时间来提高程序的性能;

Safepoint
GC回收就像是公司的保洁阿姨在打扫卫生,如果打扫过程中,有一直人在扔垃圾怎么办,其实很简单,让保洁阿姨在打扫前和办公室成员说要开始打扫了,现在不允许扔垃圾,这就好啦,所以在JVM即将要回收时,Safepoint(安全点)会有以下几个特点:

1.分析过程中对象引用关系不会发生变化的点
2.产生Safepoint的地方:方法调用;循环跳转;异常跳转等,如果GC时发现当前线程不再安全点,那就会等待;
3.安全点数量适中,不能太多,太多了GC很频繁触发,增加程序运行的负荷,太少GC要等很久;

九、常见的垃圾收集器

首先插个小内容:
JVM的运行模式有两种,分别是Server和Client,Server启动比Client慢,但是稳定之后,Server的运行比Client快,因为Server使用的是重量级的JVM虚拟机,重量级的虚拟机做了更多的优化,通过java -version命令可以查看当前是使用哪种模式启动;
在这里插入图片描述
年轻代常见的垃圾收集器
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
老年代常见的垃圾收集器

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2021-07-30 12:36:58  更:2021-07-30 12:38:00 
 
开发: 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年4日历 -2024/4/28 22:37:27-

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