我的编程空间,编程开发者的网络收藏夹
学习永远不晚

JVM分代垃圾回收机制和垃圾回收算法

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

JVM分代垃圾回收机制和垃圾回收算法

 一、什么是GC

​ GC (Garbage Collection)垃圾回收,顾名思义就是专门回收垃圾的。,在C/C++中,我们需要用到内存的时候,需要先手动申明一下,使用完后又需要在手动回收一下,这两部非常麻烦而且还经常会出这个方面的问题。而这一切在Java中就已经被自动执行掉了,所以我们写代码的时候都不用再管这些无效的数据。

二、GC分类

​ 在目前主流的虚拟机中,大多都是根据分代收集的理论来进行设计的。因为在虚拟机中绝大部分的对象都是朝生夕死的,而熬过了多次的垃圾回收后的对象就越难被回收。所以前面的理论堆就被划分成了两个区域,新生代和老年代,前者主要存储那些朝生夕死的对象,后者存放难死的对象。

​ 1、 新生代回收(Minor GC/Young GC):指只是进行新生代的回收。

​ 2、老年代回收(Major GC/Old GC):指只是进行老年代的回收。目前只有 CMS 垃圾回收器会有这个单独的回收老年代的行为。 (Major GC 定义是比较混乱,有说指是老年代,有的说是做整个堆的收集,这个需要你根据别人的场景来定,没有固定的说法)

​ 3、整堆回收(Full GC):收集整个 Java 堆和方法区(注意包含方法区)

三、垃圾回收算法

1、复制算法(Copying)

​ 将一块内存区域进行对半分,当有一半的内存使用完时将还存活的对象放到另一半内存区域中,原来的内存区域进行回收,不用考虑内存碎片区域,只要按顺序分配内存就行。实现简单,运行高效。

​ 但是这样也有个缺点就是对内存的利用率只有50%,于是在JVM中就有了以下的解决办法:

Appel式回收

​ Eden区的添加,一般来说的内存区域的分配为:Eden:80%,Survivor:20%(From 10%,To 10%),当Survivor区不够用的时候,就需要老年代进行分配担保。

2、标记-清除法(Mark-Sweep)

​ 算法分为“标记”和“清理”两个阶段:第一步扫描需要标记所有可以被回收的对象,第二遍扫描需要清理被第一步标记的对象,效率略低。因为需要大量的标记对象和清除所以回收效率是不复制算法的,如果大部分的对象是朝生夕死的那么标记的对象就会更多,效率会更低。

​ 它还有个主要问题就是会产生大量的内存碎片导致大对象无法进行存储,从而不得不提前触发其他的垃圾回收。

3、标记-整理法(Mark-Compact )

​ 步骤与清除法步骤一致但是,它的第二步是整理标记之外的所有对象,将所有对象向前移动之后直接清除掉这些对象所在之外的内存区域。标记法不会存在内存碎片,但是效率是遍低的。

​ 整理法和清除法的主要区别就是一个是回收对象,一个整理对象,而移动对象还会需要暂停所有的业务线程后更新所有对象的引用(直接指针需要调整)。

四、JVM垃圾回收器

 

1、Serial/Serial Old

​ JVM诞生初期所采用的垃圾回收器,单线程,独占式,适合单CPU。

​ 它只适合堆内存几十兆到几百兆,如果超过的这个内存的大小则会大大的降低回收效率,所以在目前很鸡肋。

 

Stop The World(STW)

​ 单线程进行垃圾回收时,必须暂停所有的工作线程,直到它回收结束。这个暂停称之为“Stop The World”,但是这种 STW 带来了恶劣的用户体验,例如:应用每运行一个小时就需要暂停响应 5 分。这个也是早期 JVM 和 java 被 C/C++ 语言诟病性能差的一个重要原因。所以 JVM 开发团队一直努力消除或降低 STW 的时间。

2、Parallel/Parallel Old

​ 为了提高JVM的回收效率,从JDK 1.3开始,JVM使用了多线程的垃圾回收器,关注吞吐量的垃圾回收器,可以更高效的利用CPU时间,从而尽快完成程序的运算任务。

​ 所谓吞吐量就是 CPU 用于运行用户代码的时间与 CPU 总消耗时间的比值,即吞吐量=运行用户代码时间/(运行用户代码时间+垃圾收集时间),虚拟机总 共运行了 100 分钟,其中垃圾收集花掉 1 分钟,那吞吐量就是 99%。

​ 该垃圾回收器适合回收堆空间上百兆~几个G。

JVM参数设置

JDK1.8 默认就是以下组合

-XX:+UseParallelGC 新生代使用 Parallel Scavenge,老年代使用 Parallel Old

-XX:MaxGCPauseMillis

 

不过不要异想天开地认为如果把这个参数的值设置得更小一点就能使得系统的垃圾收集速度变得更快,垃圾收集停顿时间缩短是以牺牲吞吐 量和新生代空间为代价换取的:系统把新生代调得小一些,收集 300MB 新生代肯定比收集 500MB 快,但这也直接导致垃圾收集发生得更频繁,原来 10 秒收集一次、每次停顿 100 毫秒,现在变成 5 秒收集一次、 每次停顿 70 毫秒。停顿时间的确在下降,但吞吐量也降下来了。

-XX:GCTimeRatio

-XX:GCTimeRatio 参数的值则应当是一个大于 0 小于 100 的整数,也就是垃圾收集时间占总时间的比率,相当于吞吐量的倒数。

例如:把此参数设置为 19, 那允许的最大垃圾收集时占用总时间的 5% (即 1/(1+19)), 默认值为 99,即允许最大 1% (即 1/(1+99))的垃圾收集时间由于与吞吐量关系密切,ParallelScavenge 是“吞吐量优先垃圾回收器”。

-XX:+UseAdaptiveSizePolicy

-XX:+UseAdaptiveSizePolicy (默认开启)。这是一个开关参数, 当这个参数被激活之后,就不需要人工指定新生代的大小(-Xmn)、Eden 与 Survivor 区的比例(-XX:SurvivorRatio)、 晋升老年代对象大小(-XX:PretenureSizeThreshold)等细节参数了,虚拟机会根据当前系统的运行情况收集性能监控信息,动态调整这些参数以提供最合适的停顿时间或者最大的吞吐量。

 

3、ParNew/CMS

ParNew

​ 多线的垃圾回收器与Parallel差不多,唯一的区别:多线程,多 CPU 的,停顿时间比 Serial 少。(在 JDK9 以后,把 ParNew 合并到了 CMS 了) 。

Concurrent Mark Sweep(CMS)


 

 

​ 此类垃圾回收器是追求最短的回收停顿时间(STW)为目标的。目前还有是很大一部分的 Java 应用集中在互联网或者 B/S 系统的服务端上,这类应用比较重视服务的响应速度,希望停顿时间更短以提升用户的体验。

​ Mark Sweep 从名字上可以看出来,这个回收器采用的是标记 - 清除法。而它的步骤比起前面的几个回收器都更麻烦些。

​ 整体过程分为 4 个步骤:

​ 初始标记:只标记与 GC Root 有直接关联的对象,这类的对象比较少,标记快。

​ 并发标记:标记与初始化标记的对象有关联的所有对象,这类的对象比较多所以采用的并发,与用户线程一起跑。

​ 重新标记:修正那些并发标记时候标记产生异动的对象标记,这块的时间比初始标记稍长一些,但是比起并发标记要快很多。

​ 并发清除:与用户线程一起运行,进行对象回收。

-XX:+UseConcMarkSweepGC ,表示新生代使用 ParNew,老年代的用 CMS。

缺点:

​ CPU敏感:因为采用的并发的技术所以对处理器的核心要求较大。

​ 浮动垃圾:在CMS进行并发清楚的时候因为采用的是并发的轻快,所以在清除的时候用户线程会产出新的垃圾。

​ 因此在进行回收的时候需要预留一部分的空间来存放这些产生垃圾(JDK 1.6 设置的阈值为92%)。

​ 但是如果用户线程产出的垃圾比较快,预留内存放不下的时候就会出现 Concurrent Mode Failure,这时虚拟机将临时启用 Serial Old 来替代 CMS。

​ 内存碎片:因为采用的是 标记 - 清除 法所以会产生内存碎片。

特点:

​ 总体来说因为 CMS 是 JVM 产生的第一个并发垃圾收集器,所以还是具有代表性的。为什么采用 标记 - 清除 法,因为在实现 CMS 的时候如果还整理对象的话,那么需要再暂停业务线程,进行一个对象的整理那么 STW 的时间会更长,为了追求 STW 的时间所以没有采用 标记 - 整理。

但是最大的问题是 CMS 采用了标记清除算法,所以会有内存碎片,当碎片较多时,给大对象的分配带来很大的麻烦,为了解决这个问题,CMS 提供一个 参数:-XX:+UseCMSCompactAtFullCollection,一般是开启的,如果分配不了大对象,就进行内存碎片的整理过程。 这个地方一般会使用 Serial Old ,因为 Serial Old 是一个单线程,所以如果内存空间很大、且对象较多时,CMS 发生这样情况会很卡。

​ 该垃圾回收器适合回收堆空间几个 G~ 20G 左右。

4、 Garbage First (G1)

​ G1 垃圾回收器的设计思想与前面所有的垃圾回收器的都不一样,前面垃圾回收器采用的都是 分代划分 的方式进行设计的,而 G1 则是将堆看作是一个整体的区域,这个区域被划分成了一个个大小一致的独立区域(Region),而每个区域都可以根据需要扮演Eden、Survivor以及老年代区域。当进行对象回收的时候就可以根据每个区域的情况进行一个回收,从而效率。

Region

​ 上面讲到除了每个Region可以扮演不同的区域,还有一个类似老年代的区域 Humongous 区域,用来专门存放大对象的。当一个对象超过了Region区空间的一半大小则判定为大对象。(每个 Region 的大小可以通过参数-XX:G1HeapRegionSize 设定,取值范围为 1MB~32MB,且应为 2 的 N 次 幂。)

​ 而对于那些超过了整个 Region 容量的超级大对象,将会被存放在 N 个连续的 Humongous Region 之中,G1 的进行回收大多数情况下都把 Humongous Region 作为老年代的一部分来进行看待。

 

开启参数 :-XX:+UseG1GC `

分区大小:-XX:+G1HeapRegionSize

 


 

 

 

一般建议逐渐增大该值,随着 size 增加,垃圾的存活时间更长,GC 间隔更长,但每次 GC 的时间也会更长。

最大 GC 暂停时间 :-XX:MaxGCPauseMillis

 

运行过程

 

G1 的运作过程大致可划分为以下四个步骤:

​ 初始标记 (Initial Marking) :标记与 GC Roots 能关联到的对象,修改 TAMS 指针的值,这个过程是需要暂停用户线程的,但是耗时非常的短。

​ TAMS (Top at Mark Start):当进行下一步并发标记的时候用户线程是会产生新的对象的,而这些对象是被判定为可存活对象而非垃圾。这个时候就需要划分一小块区域来存放这这些对象。

​ 并发标记 (Concurrent Marking):进行扫描标记所有课回收的对象。当扫描完成后,并发会有引用变化的对象,而这些对象会漏标这些漏标的对象会被 SATB 算法所解决。

​ SATB(snapshot-at-the-beginning):类似快照,对当前区域进行一个快照的保存,之后再最终标记的时候进行对比查看漏标的会被重新标记上(后面的文章会详解)。

​ 最终标记 (Final Marking): 暂停所有的用户线程,对之前漏标的对象进行一个标记。

​ 筛选回收( Live Data Counting and Evacuation):更新Region的统计数据,对各个 Region 的回收价值进行一个排序,根据用户所设置的停顿时间制定一个回收计划,自由选择任意个 Region 进行回收。将需要回收的Region 复制到空的 Region 区域中,再清除掉原来的整个Region区域。这块还涉及到对象的移动所以需要暂停所有的用户线程,有多条回收器线程进行完成。

特点:

​ 并行与并发:G1 能充分利用多 CPU、多核环境下的硬件优势,使用多个 CPU(CPU 或者 CPU 核心)来缩短 Stop-The-World 停顿的时间,部分其他收集器

原本需要停顿 Java 线程执行的 GC 动作,G1 收集器仍然可以通过并发的方式让 Java 程序继续执行。

​ 分代收集:与其他收集器一样,分代概念在 G1 中依然得以保留。虽然 G1 可以不需要其他收集器配合就能独立管理整个 GC 堆,但它能够采用不同的方式

去处理新创建的对象和已经存活了一段时间、熬过多次 GC 的旧对象以获取更好的收集效果。

​ 空间整合:与 CMS 的“标记—清理”算法不同,G1 从整体来看是基于“标记—整理”算法实现的收集器,从局部(两个 Region 之间)上来看是基于“复制”算法实现的,但无论如何,这两种算法都意味着 G1 运作期间不会产生内存空间碎片,收集后能提供规整的可用内存。这种特性有利于程序长时间运行,分配大对象时不会因为无法找到连续内存空间而提前触发下一次 GC。

​ 追求停顿时间:-XX:MaxGCPauseMillis 指定目标的最大停顿时间,G1 尝试调整新生代和老年代的比例,堆大小,晋升年龄来达到这个目标时间。

​ 该垃圾回收器适合回收堆空间上百 G。一般在 G1 和 CMS 中间选择的话平衡点在 6~8G,只有内存比较大 G1 才能发挥优势

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

JVM分代垃圾回收机制和垃圾回收算法

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

JVM分代垃圾回收机制和垃圾回收算法

在C/C++中,我们需要用到内存的时候,需要先手动申明一下,使用完后又需要在手动回收一下,这两部非常麻烦而且还经常会出这个方面的问题。而这一切在Java中就已经被自动执行掉了,所以我们写代码的时候都不用再管这些无效的数据。
JVM回收算法2024-12-02

JVM 垃圾回收算法和 CMS 垃圾回收器

本文核心主要是讲述:JVM 中的几种垃圾回收算法理论,以及多种垃圾收集器,并且详细参数 CMS 垃圾收集器的实现、优缺点等,最后也会解释一下三色标记法与读写屏障。

详解JVM 的垃圾回收算法和垃圾回收器

为了让这部分动态的内存分配能够进行合理的回收,就需要垃圾回收算法和垃圾回收器来帮忙了。下面让我们进入今天的主题。

JVM基本垃圾回收算法

这篇文章主要介绍“JVM基本垃圾回收算法”,在日常操作中,相信很多人在JVM基本垃圾回收算法问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”JVM基本垃圾回收算法”的疑惑有所帮助!接下来,请跟着小编一起来学习吧
2023-06-17

垃圾回收机制

我们定义变量会申请内存空间来存放变量的值,而内存的容量是有限的,当一个变量值没有用了(称为垃圾),就应该将其占用的内存给回收掉。变量名是访问到变量的唯一方式,所以当一个变量值没有任何关联的变量名时,我们就无法访问到该变量了,该变量就是一个垃
2023-01-30

有哪些jvm垃圾回收算法

这篇文章将为大家详细讲解有关有哪些jvm垃圾回收算法,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。jvm垃圾回收算法:1、“标记–清除”算法;首先标记出所有需要被回收的对象,然后在标记完成后
2023-06-14

python垃圾回收机制!

python的三种垃圾回收机制:1.python采用的是引用计数机制为主;2.标记-清除;为辅的策略3.分代收集(隔代回收、分代回收)为辅的策略现在的高级语言如java,c#等,都采用了垃圾收集机制,而不再是c,c++里用户自己管理维护内存
2023-01-31

day09(垃圾回收机制)

1,复习文件处理1.操作文件的三步骤 -- 打开文件:硬盘的空间被操作系统持有 | 文件对象被应用程序持续 -- 操作文件:读写操作 -- 释放文件:释放操作系统对硬盘空间的持有 2.基础的读写with open('
2023-01-31

JVM垃圾回收算法的示例分析

这篇文章主要介绍了JVM垃圾回收算法的示例分析,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。新一代JVM垃圾回收算法JVM垃圾回收的瓶颈传统分代JVM垃圾回收方式,已经在一定
2023-06-17

JVM调优之垃圾定位、垃圾回收算法、垃圾处理器对比

谈垃圾回收器之前,要先讲讲垃圾回收算法,以及JVM对垃圾的认定策略,JVM垃圾回收器是垃圾回收算法的具体实现,了解了前面的前置知识,有利于对垃圾回收器的理解。

jvm回收垃圾的机制是什么

JVM(Java虚拟机)使用自动垃圾回收(Garbage Collection)机制来管理和回收不再使用的对象的内存。以下是JVM垃圾回收的机制:1. 引用计数:这是一种最简单的垃圾回收机制,它通过对每个对象维护一个引用计数器来记录当前有多
2023-08-30

JVM垃圾回收机制有什么用

这篇文章主要介绍JVM垃圾回收机制有什么用,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!1.JVM的gc概述gc即垃圾收集机制是指jvm用于释放那些不再使用的对象所占用的内存。java语言并不要求jvm有gc,也没有
2023-06-17

浅谈一下JVM垃圾回收算法

这篇文章主要介绍了一下JVM垃圾回收算法,Java有着自己一套的内存管理机制,不需要开发者去手动释放内存,开发者只需要写好代码即可,运行过程中产生的垃圾都由JVM回收,需要的朋友可以参考下
2023-05-18

JVM中垃圾回收机制的示例分析

这篇文章主要介绍了JVM中垃圾回收机制的示例分析,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。堆内存的划分分为三个部分(以下名词表示同一个区):新生区、新生代、年轻代养老区、
2023-06-29

JavaGC垃圾回收算法分析

垃圾回收机制简称GC,主要用于Java堆的管理。在JVM中程序计数器、虚拟机栈、本地方法栈生命周期随跟随线程,栈帧的进栈和入栈能实现自动清理。而jdk8后元空间为本地内存也不受GC控制,所以垃圾回收主要是在堆中
2022-12-20

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录