Full GC为什么那么慢?为什么老年代垃圾回收效率比新生代低很多?为什么Minor gc速度比Major GC慢?

2024-01-01 20:32

本文主要是介绍Full GC为什么那么慢?为什么老年代垃圾回收效率比新生代低很多?为什么Minor gc速度比Major GC慢?,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

GC类型分为三种:

Yong GC

Old GC

MIXED GC

Full GC

(有些文章和书上也叫Minor GC、Major GC、Full GC,由于Major GC的意思有些混淆,所以改成Old GC容易理解)


GC回收的“无用的类”(元数据区):
1、该类所有的实例都已经被回收,也就是Java堆中不存在该类的任何实例
2、加载该类的 ClassLoader已经被回收
3、该类对应的java.lang.Class对象没有在任何地方被引用,无法在任何地方通过反射访问该类的方法


JVM性能调优主要目的是避免Full GC的发生

Full GC的慢,其实是相对于Yong GC和Old GC。


Yong GC回收新生代

Old GC回收年老代,个别JVM参数配置设置了Old GC之前必须执行一次Yong GC

MIXED GC回收新生代+老年代,G1回收算法

Full GC回收新生代、老年代、元数据区/永久代


Full GC为什么那么慢?

1、元数据区的回收算法效率低,虚拟机规范Class回收条件比较苛刻


2、Full GC回收新生代、老年代、元数据区/永久代。从这个角度讲,多回收了方法区,增加了总的回收耗时。(有些文章提到Full GC能回收堆外直接内存,这个说法并不准确,本质上是JVM一个后台线程,通过虚引用遍历堆里已经被回收的对象对直接内存的直接引用,显示的调用free()方法释放直接内存,Full GC不能直接释放堆外直接内存。总之,堆外直接内存的释放,和GC方式类型无关)


3、Full GC本身不会先进行Minor GC,我们可以配置-XX:+ScavengeBeforeFullGC(非CMS回收算法)、CMSScavengeBeforeRemark(CMS回收算法)可以,让Full GC之前先进行一次Minor GC,因为老年代很多对象都会引用到新生代的对象,先进行一次Minor GC可以提高老年代GC的速度。

(G1回收算法除外,G1回收有一个MIXED回收阶段,新生代和老年代都一起回收,与配置的JVM参数无关)


4、CMS发生了concurrent mode fail,young区使用ParNew(并行GC),Old+Perm(单独设置)使用CMS,整个堆(young+old+metaspace/perm)使用MSC(Mark Sweep Compact)是CMS GC算法的Full GC算法,单线程回收整个堆,回收过程有严格的步骤,碎片压缩,它是单线程的标记-压缩收集器,所以耗时非常的长。

(单线程、碎片压缩,由于并发失败,不能继续并发回收,STOP-THE-WORD回收效率是必要的,系统的内存很紧张了,好多新对象在着急的等着分配内存,不允许你再慢慢的并发回收内存,但这意味着停顿时间的大幅度增加)


5、G1发生了concurrent mode fail之后退化成了单线程回收整个堆




为什么老年代垃圾回收效率比新生代低很多?

为什么Yong GC比Old GC慢?为什么Minor gc速度比Major GC慢?

这里的Yong GC=Minor gc,Old GC=Major GC

Old GC的速度一般会比yong gc慢10倍以上


1、从并行和并发机制,并行和并发的默认线程数上,可以看出-XX:ConcGCThreads=(-XX:ParallelGCThreads + 3)/ 4

(XX:ParallelGCThreads是并行线程数,XX:ConcGCThreads是并发线程数)

(并行是STOP-THE-WORD,并发是回收垃圾的时候,应用查询继续在执行)

2、(时间换空间s1、s2)新生代复制算法比较快。Eden区回收时直接全部清空,存活的对象存放到内存容量比较小的s1,少了解决内存碎片整理  加上直接copy的速度,效率很高。


3、(新生代GC根据卡表,只需扫描部分老年代)卡表数据库结构,卡表为一个比特位的集合,卡表中每一位表示老年代4KB的空间,每一个比特位可以用来表示老年代的某一区域中的所有对象是否持有新生代对象的引用。
这样新生代GC时,可以不用花大量时间扫码所有老年代对象,来确定每一个对象的引用关系,
而可以先扫码卡表,只有卡表的标记位为1时,才需要扫码给定区域的老年代对象
而卡表位为0的锁住区域的老年代对象,一定不含有新生代对象的引用


4、(空间换时间),老年代标记清除算法会导致内存碎片化,因此就引入了标记整理算法,执行完毕后,存活的对象会按序放置,移动对象的内存地址(重点),来解决碎片化,但是执行时间较长。


5、老年代区内存容量一般较大,回收需要预留比较大的空间(老年代GC是并发执行,重新标记的时候修正引用关系),这样的话内存利用率就低(相对于新生代利用率eden+from=90%,新生代存活率低不需要预留太多内存)



这篇关于Full GC为什么那么慢?为什么老年代垃圾回收效率比新生代低很多?为什么Minor gc速度比Major GC慢?的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/560434

相关文章

Java下载文件中文文件名乱码的解决方案(文件名包含很多%)

《Java下载文件中文文件名乱码的解决方案(文件名包含很多%)》Java下载文件时,文件名中文乱码问题通常是由于编码不正确导致的,使用`URLEncoder.encode(filepath,UTF-8... 目录Java下载文件中文文件名乱码问题一般情况下,大家都是这样为了解决这个问题最终解决总结Java下

MySQL报错sql_mode=only_full_group_by的问题解决

《MySQL报错sql_mode=only_full_group_by的问题解决》本文主要介绍了MySQL报错sql_mode=only_full_group_by的问题解决,文中通过示例代码介绍的非... 目录报错信息DataGrip 报错还原Navicat 报错还原报错原因解决方案查看当前 sql mo

使用DeepSeek API 结合VSCode提升开发效率

《使用DeepSeekAPI结合VSCode提升开发效率》:本文主要介绍DeepSeekAPI与VisualStudioCode(VSCode)结合使用,以提升软件开发效率,具有一定的参考价值... 目录引言准备工作安装必要的 VSCode 扩展配置 DeepSeek API1. 创建 API 请求文件2.

C#使用yield关键字实现提升迭代性能与效率

《C#使用yield关键字实现提升迭代性能与效率》yield关键字在C#中简化了数据迭代的方式,实现了按需生成数据,自动维护迭代状态,本文主要来聊聊如何使用yield关键字实现提升迭代性能与效率,感兴... 目录前言传统迭代和yield迭代方式对比yield延迟加载按需获取数据yield break显式示迭

离心萃取机废旧磷酸铁锂电池回收工艺流程

在废旧磷酸铁锂电池的回收工艺流程中,离心萃取机主要应用于萃取除杂的步骤,以提高回收过程中有价金属(如锂)的纯度。以下是结合离心萃取机应用的废旧磷酸铁锂电池回收工艺流程: 电池拆解与预处理 拆解:将废旧磷酸铁锂电池进行拆解,分离出电池壳、正负极片、隔膜等部分。破碎与筛分:将正负极片进行破碎处理,并通过筛分将不同粒径的物料分开,以便后续处理。 浸出与溶解 浸出:采用适当的浸出工艺(如二段式逆

【编程底层思考】垃圾收集机制,GC算法,垃圾收集器类型概述

Java的垃圾收集(Garbage Collection,GC)机制是Java语言的一大特色,它负责自动管理内存的回收,释放不再使用的对象所占用的内存。以下是对Java垃圾收集机制的详细介绍: 一、垃圾收集机制概述: 对象存活判断:垃圾收集器定期检查堆内存中的对象,判断哪些对象是“垃圾”,即不再被任何引用链直接或间接引用的对象。内存回收:将判断为垃圾的对象占用的内存进行回收,以便重新使用。

HotSpot虚拟机的经典垃圾收集器

读《深入理解Java虚拟机》第三版笔记。 关系 Serial、ParNew、Parallel Scavenge、Parallel Old、Serial Old(MSC)、Concurrent Mark Sweep (CMS)、Garbage First(G1)收集器。 如图: 1、Serial 和 Serial Old 收集器 2、ParNew 收集器 3、Parallel Sc

为什么现在很多人愿意选择做债务重组?债重组真的就这么好吗?

债务重组,起初作为面向优质企业客户的定制化大额融资策略,以其高效周期著称,一个月便显成效。然而,随着时代的车轮滚滚向前,它已悄然转变为负债累累、深陷网贷泥潭者的救赎之道。在此路径下,个人可先借助专业机构暂代月供,经一段时间养护征信之后,转向银行获取低成本贷款,用以替换高昂网贷,实现利息减负与成本优化的双重目标。 尽管债务重组的代价不菲,远超传统贷款成本,但其吸引力依旧强劲,背后逻辑深刻。其一

浅谈PHP5中垃圾回收算法(Garbage Collection)的演化

前言 PHP是一门托管型语言,在PHP编程中程序员不需要手工处理内存资源的分配与释放(使用C编写PHP或Zend扩展除外),这就意味着PHP本身实现了垃圾回收机制(Garbage Collection)。现在如果去PHP官方网站(php.net)可以看到,目前PHP5的两个分支版本PHP5.2和PHP5.3是分别更新的,这是因为许多项目仍然使用5.2版本的PHP,而5.3版本对5.2并不是完

多数据源的事务处理总是打印很多无用的log日志

之前做了一个项目,需要用到多数据源以及事务处理,在使用事务处理,服务器总是打印很多关于事务处理的log日志(com.atomikos.logging.Slf4jLogger),但是我们根本不会用到这些log日志,反而使得查询一些有用的log日志变得困难。那要如何屏蔽这些log日志呢? 之前的项目是提高项目打印log日志的级别,后来觉得这样治标不治本。 现在有一个更好的方法: 我使用的是log