爆款云主机2核4G限时秒杀,88元/年起!
查看详情

活动

天翼云最新优惠活动,涵盖免费试用,产品折扣等,助您降本增效!
热门活动
  • 618智算钜惠季 爆款云主机2核4G限时秒杀,88元/年起!
  • 免费体验DeepSeek,上天翼云息壤 NEW 新老用户均可免费体验2500万Tokens,限时两周
  • 云上钜惠 HOT 爆款云主机全场特惠,更有万元锦鲤券等你来领!
  • 算力套餐 HOT 让算力触手可及
  • 天翼云脑AOne NEW 连接、保护、办公,All-in-One!
  • 中小企业应用上云专场 产品组合下单即享折上9折起,助力企业快速上云
  • 息壤高校钜惠活动 NEW 天翼云息壤杯高校AI大赛,数款产品享受线上订购超值特惠
  • 天翼云电脑专场 HOT 移动办公新选择,爆款4核8G畅享1年3.5折起,快来抢购!
  • 天翼云奖励推广计划 加入成为云推官,推荐新用户注册下单得现金奖励
免费活动
  • 免费试用中心 HOT 多款云产品免费试用,快来开启云上之旅
  • 天翼云用户体验官 NEW 您的洞察,重塑科技边界

智算服务

打造统一的产品能力,实现算网调度、训练推理、技术架构、资源管理一体化智算服务
智算云(DeepSeek专区)
科研助手
  • 算力商城
  • 应用商城
  • 开发机
  • 并行计算
算力互联调度平台
  • 应用市场
  • 算力市场
  • 算力调度推荐
一站式智算服务平台
  • 模型广场
  • 体验中心
  • 服务接入
智算一体机
  • 智算一体机
大模型
  • DeepSeek-R1-昇腾版(671B)
  • DeepSeek-R1-英伟达版(671B)
  • DeepSeek-V3-昇腾版(671B)
  • DeepSeek-R1-Distill-Llama-70B
  • DeepSeek-R1-Distill-Qwen-32B
  • Qwen2-72B-Instruct
  • StableDiffusion-V2.1
  • TeleChat-12B

应用商城

天翼云精选行业优秀合作伙伴及千余款商品,提供一站式云上应用服务
进入甄选商城进入云市场创新解决方案
办公协同
  • WPS云文档
  • 安全邮箱
  • EMM手机管家
  • 智能商业平台
财务管理
  • 工资条
  • 税务风控云
企业应用
  • 翼信息化运维服务
  • 翼视频云归档解决方案
工业能源
  • 智慧工厂_生产流程管理解决方案
  • 智慧工地
建站工具
  • SSL证书
  • 新域名服务
网络工具
  • 翼云加速
灾备迁移
  • 云管家2.0
  • 翼备份
资源管理
  • 全栈混合云敏捷版(软件)
  • 全栈混合云敏捷版(一体机)
行业应用
  • 翼电子教室
  • 翼智慧显示一体化解决方案

合作伙伴

天翼云携手合作伙伴,共创云上生态,合作共赢
天翼云生态合作中心
  • 天翼云生态合作中心
天翼云渠道合作伙伴
  • 天翼云代理渠道合作伙伴
天翼云服务合作伙伴
  • 天翼云集成商交付能力认证
天翼云应用合作伙伴
  • 天翼云云市场合作伙伴
  • 天翼云甄选商城合作伙伴
天翼云技术合作伙伴
  • 天翼云OpenAPI中心
  • 天翼云EasyCoding平台
天翼云培训认证
  • 天翼云学堂
  • 天翼云市场商学院
天翼云合作计划
  • 云汇计划
天翼云东升计划
  • 适配中心
  • 东升计划
  • 适配互认证

开发者

开发者相关功能入口汇聚
技术社区
  • 专栏文章
  • 互动问答
  • 技术视频
资源与工具
  • OpenAPI中心
开放能力
  • EasyCoding敏捷开发平台
培训与认证
  • 天翼云学堂
  • 天翼云认证
魔乐社区
  • 魔乐社区

支持与服务

为您提供全方位支持与服务,全流程技术保障,助您轻松上云,安全无忧
文档与工具
  • 文档中心
  • 新手上云
  • 自助服务
  • OpenAPI中心
定价
  • 价格计算器
  • 定价策略
基础服务
  • 售前咨询
  • 在线支持
  • 在线支持
  • 工单服务
  • 建议与反馈
  • 用户体验官
  • 服务保障
  • 客户公告
  • 会员中心
增值服务
  • 红心服务
  • 首保服务
  • 客户支持计划
  • 专家技术服务
  • 备案管家

了解天翼云

天翼云秉承央企使命,致力于成为数字经济主力军,投身科技强国伟大事业,为用户提供安全、普惠云服务
品牌介绍
  • 关于天翼云
  • 智算云
  • 天翼云4.0
  • 新闻资讯
  • 天翼云APP
基础设施
  • 全球基础设施
  • 信任中心
最佳实践
  • 精选案例
  • 超级探访
  • 云杂志
  • 分析师和白皮书
  • 天翼云·创新直播间
市场活动
  • 2025智能云生态大会
  • 2024智算云生态大会
  • 2023云生态大会
  • 2022云生态大会
  • 天翼云中国行
天翼云
  • 活动
  • 智算服务
  • 产品
  • 解决方案
  • 应用商城
  • 合作伙伴
  • 开发者
  • 支持与服务
  • 了解天翼云
      • 文档
      • 控制中心
      • 备案
      • 管理中心

      jvm专题(3) - 【1/3】GC基础

      首页 知识中心 其他 文章详情页

      jvm专题(3) - 【1/3】GC基础

      2023-05-19 02:20:27 阅读次数:112

      GC,jvm

      此章笔者会多写点,分三个子专题来讲述:理论基础、实操、工具使用。目的是争取使读者一次性弄懂。不需要再反反复复的查各种资料,笔者也会把之前踩过的坑也详细描述下,防止读者再走笔者的弯路。

      牢记:可被GC管理的内存区只有堆和方法区,其它3个私有区都会随着线程终止而释放。

      一、GC基础

      笔者看过很多文章,在面试时也问过很多候选人,发现很多人对GC的知识点并没有很清晰的总结和归类,比如会把垃圾回收算法和垃圾器类型搞混、不了解引用类型等相关知识(虽然很少用到),所以本节还是先总结一下本章的全貌,读者从逻辑上理清GC的相关知识:

      jvm专题(3) - 【1/3】GC基础

      GC又可以称为堆收集器,它作用在堆上。除了对运行期间产生新对象经过判断引用后释放所占的内存空间,还要处理堆碎块。如果不处理即使堆有足够的空间也可能因为没有连续的空间放下新对象而溢出。GC一般为分为两步来操作:1、标记;2、释放。

      GC是通过对象的finalize()终结方法来释放内存的,扩展此方法可以做一些清理工作。JVM的内存是分区的,GC可以按区来回收,否则一次GC可能会造成比较长时间的程序暂停时间(称为STW stop-the-world)。

      标记整理有时也称为标记压缩,本章节会使用标记整理这个术语。

      二、引用对象

      引用对象用于封装指向其它对象的连接,其实就是把局部/类变量包装一下,以便后绪的清理工作。被指向的目标称为引用目标。其中弱引用的三种类型都是java.lang.ref.Reference的子类。

      要创建一个弱类型的引用,可以把强引用传递到对应的引用对象的构造方法中去。比如要创建对某个A对象的软引用,就把此对象传递到java.lang.ref.Reference的构造方法中。用java.lang.ref.Reference做桥接就可以维护java.lang.ref.Reference的强引用,也维护了某个A对象的软引用。如果想切断这个软引用,可以调用java.lang.ref.Reference的clear()方法。

      1. 强引用:在 Java 中最常见的就是强引用,把一个对象赋给一个引用变量,这个引用变量就是一个强引用。当一个对象被强引用变量引用时,它处于可达状态,它是不可能被垃圾回收机制回收的,即使该对象以后永远都不会被用到 JVM 也不会回收。因此强引用是造成 Java 内存泄漏的主要原因之 一。
      2. 软引用:软引用需要用 SoftReference 类来实现,对于只有软引用的对象来说,当系统内存足够时它不会被回收,当系统内存空间不足时它会被回收。软引用通常用在对内存敏感的程序中。
      3. 弱引用:弱引用需要用 WeakReference 类来实现,它比软引用的生存期更短,对于只有弱引用的对象来说,只要垃圾回收机制一运行,不管 JVM 的内存空间是否足够,总会回收该对象占用的内存。
      4. 虚引用:又称影子引用,虚引用需要 PhantomReference 类来实现,它不能单独使用,必须和引用队列联合使用。虚引用的主要作用是跟踪对象被垃圾回收的状态。​

      2.1、引用对象的状态改变

      jvm会维护一个java.lang.ref.ReferenceQueue的引用队列,当垃圾回收器改变了对象的触及状态时,可监听此队列进行一些异步操作,这个监听器方法是由java.lang.ref.Reference定义的poll、remove等。通过把引用对象作为构造方法的参数传递到引用队列,实现队列和引用对象的关联。弱引用还需要注意gc在对象状态改变时加入队列前的清理策略。下图是引用类型的一个状态改变过程:

      jvm专题(3) - 【1/3】GC基础

      1. 强可触及:局部变量,即对象只可以从根节点而不能通过其它任何引用对象搜索到。只要根节点存在一个外部引用,那么这个局部变量类型的强可触及对象就不会被回收掉;
      2. 软可触及:对象可以从除了根节点以外的途径(未被清除掉)被搜索到,有可能被GC掉,如果GC了则会清除所有关联引用;清除掉的同时把该软引用对象放入队列java.lang.ref.ReferenceQueue的实例中。简单来说当有足够内存时就不管了,当没有足够内存时就回收了,对内存占用比较敏感
      3. 弱可触及:一定会被GC掉,如果GC了则会清除所有关联引用;清除掉的同时把该弱引用对象放入队列java.lang.ref.ReferenceQueue的实例中;
      4. 可复活的:没有任何外部引用,但还没有被GC,一般可通过finalize方法再次复活,这也是gc要进行两次扫描的原因;
      5. 虚可触及:已下确定此对象不会被任何对象引用(这有区别于不可触及),即将被回收。但是如果被复活。此类对象不会被GC掉,需要程序显示的释放,同时把该影子引用对象放入队列java.lang.ref.ReferenceQueue的实例中;因为需要手动清除;
      6. 不可触及:必被回收,并且一旦对象达到这个状态后其状态不可更改,只能被GC;

      2.2、引用对象的适应场景

      1. 软引用:适合创建内存中的缓存的场景,它与程序整体内存情况有关;比方说从外部读取的文件内容,只要内存足够多,jvm都可以选择在堆中缓存而不清除,所以对于这类应用应该把堆设置的大一点,判断后再回收
      2. 弱引用:适合创建映射,比如hash映射,当程序中不再引用相关映射时就可以释放了,发现即回收;
      3. 虚引用:适合实现在终结方法finalize()之后的比较复杂的临终清理和动作,因其不可被GC,所以需要显示的调用clear()方法清除引用对象,把影子可触及状态转变为不可触及状态,跟踪后再回收

      三、垃圾收集算法

      这一节主要描述jvm收回收的对象是如何标记出来的,标记后才能转给gc回收器进行垃圾回收,不要把垃圾收集算法和垃圾回收算法这两个概念弄混了。

      3.1、引用计数收集算法

      在 Java 中,引用和对象是有关联的。如果要操作对象则必须用引用进行。因此,很显然一个简单的办法是通过引用计数来判断一个对象是否可以回收。简单说,即一个对象如果没有任何与之关 联的引用,即他们的引用计数都不为 0,则说明对象不太可能再被用到,那么这个对象就是可回收对象。

      原理就是:为堆中的每一个对象创建一个计数器,解析到引用则计数+1,当一个对象的生存期或被设置为一个新值时,计数-1。当计数为0时就可以标记为垃圾,当它被回收时,它引用的任何对象的计数都-1。这样就有可能形成连续回收的机制。

      • 优点:执行快;
      • 缺点:无法处理循环依赖引用,所以在jvm中没有采用这种算法

      3.2、跟踪收集算法

      又称标记并清除算法,从对象的根节点,创建一张对象引用图,然后追踪打标,当追踪结束时,未被打标的可认为可被回收。不可达对象变为可回收对象至少要经过两次标记过程。为了解决引用计数法的循环引用问题,Java 使用了可达性分析的方法。通过一系列的“GC roots”对象作为起点搜索。如果在“GC roots”和一个对象之间没有可达路径,则称该对象是不可达的。

      要注意的是,不可达对象不等价于可回收对象,不可达对象变为可回收对象至少要经过两次标记过程。两次标记后仍然是可回收对象,则将面临回收。

      3.3、*分区收集算法

      这不是一个具体的算法,可以理解为上述算法的优化,叫分区收集,使用多种算法同时并存,根据配置等自由切换。把堆按对象存活周期分为多个子堆。优先频繁回收young,因这个子堆可多数为临时变量。在一起收集后,对于依然存活的对象需要重新分配子堆。

      分区算法则将整个堆空间划分为连续的不同小区间, 每个小区间独立使用, 独立回收. 这样做的好处是可以控制一次回收多少个小区间, 根据目标停顿时间, 每次合理地回收若干个小区间(而不是整个堆), 从而减少一次 GC 所产生的停顿。在CMS和G1垃圾回收器中有有具体的体现。

      四、垃圾回收算法

      4.1、标记清除

      最基础的垃圾回收算法,分为两个阶段,标注和清除。标记阶段标记出所有需要回收的对象,清除阶段回收被标记的对象所占用的空间。如图:

      jvm专题(3) - 【1/3】GC基础

      从图中我们就可以发现,该算法最大的问题是内存碎片化严重,后续可能发生大对象不能找到可 利用空间的问题。

      4.2、复制

      为了解决 Mark-Sweep 算法内存碎片化的缺陷而被提出的算法。按内存容量将内存划分为等大小的两块。每次只使用其中一块,当这一块内存满后将尚存活的对象复制到另一块上去,把已使用的内存清掉,如图:把堆设置为双倍大小,一半空闲,一半使用。当使用块被占满时,中止程序运行,把块内容移动到空闲块的连续区域,同时在使用区保留转向指标;然后再使用空闲区直到填满。再移动。这种算法应用在了新手代eden, from, to的内存上,其中from和to区大小相同,功能可以互换,这两个区又 称为幸存区。

      jvm专题(3) - 【1/3】GC基础

      这种算法虽然实现简单,内存效率高,不易产生碎片,但是最大的问题是可用内存被压缩到了原本的一半。且存活对象增多的话,Copying 算法的效率会大大降低。

      4.3、标记整理

      结合了以上两个算法,为了避免缺陷而提出。标记阶段和 Mark-Sweep 算法相同,标记后不是清理对象,而是将存活对象移向内存的一端。然后清除端边界外的对象。如图:

      jvm专题(3) - 【1/3】GC基础

      这种算法多了一个移动的过程,其效率肯定不如上述两种算法快,同样也并不是说一概可以采用此种算法的垃圾回收器,还是需要综合服务器和应用情况择择选择。

      4.4、*分代

      这个分代和上面提到的分区是一个概念,它不是一个具体的算法,可以理解为上述算法的优化版本,分代收集法是目前大部分 JVM 所采用的方法,其核心思想是根据对象存活的不同生命周期将内存 划分为不同的域,一般情况下将 GC 堆划分为老生代(Tenured/Old Generation)和新生代(Young Generation)。老生代的特点是每次垃圾回收时只有少量对象需要被回收,新生代的特点是每次垃 圾回收时都有大量垃圾需要被回收,因此可以根据不同区域选择不同的算法。如下所示:

      4.4.1、新生代与复制算法

      目前大部分 JVM 的 GC 对于新生代都采取 Copying 算法,因为新生代中每次垃圾回收都要 回收大部分对象,即要复制的操作比较少,但通常并不是按照 1:1 来划分新生代。一般将新生代 划分为一块较大的 Eden 空间和两个较小的 Survivor 空间(From Space, To Space),每次使用Eden 空间和其中的一块 Survivor 空间,当进行回收时,将该两块空间中还存活的对象复制到另 一块 Survivor 空间中。

      4.4.2、老年代与标记复制算法

      而老年代因为每次只回收少量对象,因而采用 Mark-Compact 算法。

      1. JAVA 虚拟机提到过的处于方法区的永生代(Permanet Generation),它用来存储 class 类,常量,方法描述等。对永生代的回收主要包括废弃常量和无用的类。
      2. 对象的内存分配主要在新生代的 Eden Space 和 Survivor Space 的 From Space(Survivor 目前存放对象的那一块),少数情况会直接分配到老生代。
      3. 当新生代的 Eden Space 和 From Space 空间不足时就会发生一次 GC,进行 GC 后,Eden Space 和 From Space 区的存活对象会被挪到 To Space,然后将 Eden Space 和 From Space 进行清理。
      4. 如果 To Space 无法足够存储某个对象,则将这个对象存储到老生代。
      5. 在进行 GC 后,使用的便是 Eden Space 和 To Space 了,如此反复循环。
      6. 当对象在 Survivor 区躲过一次 GC 后,其年龄就会+1。默认情况下年龄到达 15 的对象会被 移到老生代中。

      五、垃圾回收器

      如果把垃圾回收器认为是一个方法实现,那么上述第3、4章可以认为是垃圾回收器的设计,第2章可认为是垃圾回收器的入参,对于一个方法来讲无非是执行过程(多线程还是单线程)、线程任务的问题了。可见如下草图,加深一下理解:

      jvm专题(3) - 【1/3】GC基础

      5.1、新生代

      5.1.1、Serial 垃圾收集器(单线程、复制算法)

      Serial(英文连续)是最基本垃圾收集器,使用复制算法,曾经是 JDK1.3.1 之前新生代唯一的垃圾收集器。Serial 是一个单线程的收集器,它不但只会使用一个CPU或单一线程去完成垃圾收集工 作,并且在进行垃圾收集的同时,必须暂停其他所有的工作线程,直到垃圾收集结束。

      Serial 垃圾收集器虽然在收集垃圾过程中需要暂停所有其他的工作线程,但是它简单高效,对于限定单个 CPU 环境来说,没有线程交互的开销,可以获得最高的单线程垃圾收集效率,因此 Serial垃圾收集器依然是 java 虚拟机运行在 Client 模式下默认的新生代垃圾收集器。

      5.1.2、ParNew垃圾收集器(Serial+多线程)

      ParNew 垃圾收集器其实是 Serial 收集器的多线程版本,也使用复制算法,除了使用多线程进行垃 圾收集之外,其余的行为和 Serial 收集器完全一样,ParNew 垃圾收集器在垃圾收集过程中同样也 要暂停所有其他的工作线程。ParNew 收集器默认开启和 CPU 数目相同的线程数,可以通过-XX:ParallelGCThreads 参数来限制垃圾收集器的线程数。ParNew 虽然是除了多线程外和 Serial 收集器几乎完全一样,它也是 ParNew 垃圾收集器是很多 java虚拟机运行在 Server 模式下新生代的默认垃圾收集器。

      5.1.3、Parallel Scavenge 收集器(多线程复制算法、高效)

      Parallel Scavenge 收集器也是一个新生代垃圾收集器,同样使用复制算法,也是一个多线程的垃圾收集器,它重点关注的是程序达到一个可控制的吞吐量(Thoughput,CPU 用于运行用户代码 的时间/CPU 总消耗时间,即吞吐量=运行用户代码时间/(运行用户代码时间+垃圾收集时间)), 高吞吐量可以最高效率地利用 CPU 时间,尽快地完成程序的运算任务,主要适用于在后台运算而不需要太多交互的任务。自适应调节策略也是 ParallelScavenge 收集器与 ParNew 收集器的一个 重要区别。

      5.2、老年代

      先了解一个术语:

      • Stop The World:GC 过程中分析对象引用关系,为了保证分析结果的准确性,需要通过停顿所有 Java 执行线程,保证引用关系不再动态变化,该停顿事件称为 Stop The World(STW)。

      5.2.1、SerialOld收集器(单线程标记整理算法)

      Serial Old 是 Serial 垃圾收集器年老代版本,它同样是个单线程的收集器,使用标记-整理算法,这个收集器也主要是运行在 Client 默认的 java 虚拟机默认的年老代垃圾收集器。在 Server 模式下,主要有两个用途:

      • 在 JDK1.5 之前版本中与新生代的 Parallel Scavenge 收集器搭配使用;
      • 作为年老代中使用 CMS 收集器的后备垃圾收集方案。

      新生代 Serial 与年老代 Serial Old 搭配垃圾收集过程图:

      jvm专题(3) - 【1/3】GC基础

      新生代 Parallel Scavenge 收集器与 ParNew 收集器工作原理类似,都是多线程的收集器,都使 用的是复制算法,在垃圾收集过程中都需要暂停所有的工作线程。新生代 Parallel Scavenge/ParNew 与年老代 Serial Old 搭配垃圾收集过程图:

      jvm专题(3) - 【1/3】GC基础

      5.2.2、ParallelOld收集器(多线程标记整理算法)

      Parallel Old 收集器是 Parallel Scavenge 的老年代版本,使用多线程的标记-整理算法,在 JDK1.6 才开始提供。在 JDK1.6 之前,新生代使用 ParallelScavenge 收集器只能搭配年老代的 Serial Old 收集器,只 能保证新生代的吞吐量优先,无法保证整体的吞吐量,Parallel Old 正是为了在年老代同样提供吞吐量优先的垃圾收集器,如果系统对吞吐量要求比较高,可以优先考虑新生代 Parallel Scavenge 和年老代 Parallel Old 收集器的搭配策略。新生代 Parallel Scavenge 和年老代 Parallel Old 收集器搭配运行过程图:

      jvm专题(3) - 【1/3】GC基础

      5.2.3、CMS收集器(多线程标记清除算法)

      Concurrent mark sweep(CMS)收集器是一种适用于老年代垃圾收集器,其最主要目标是获取最短垃圾回收停顿时间,和其他年老代使用标记-整理算法不同,它使用多线程并发标记清除算法,它主要关注系统停顿时间,可以不阻塞应用程序运行的同时回收垃圾。它会在内存达到某个特定的使用阀值时才触发,默认为68%。使用CMSInitiatingOccupancyFraction来指定。但当程序内存增长过快时,CMS有可能失败,这时JVM会自动启动老年代串行回收器直至GC完成,代价是有可能程序中断的时间比较长。所以当内存增长过快时此值在设置的小一些防止回收发生在老年代,它在必要时才会进行一次碎片整理。

      UseConcMarkSweepGC:默认线程数为(ParallelGCThreads+3)/ 4;

      整个过程如下图所示,分为7个阶段:

      jvm专题(3) - 【1/3】GC基础

      1. 初始标记(Initial Mark):此阶段的目标是标记老年代中所有存活的对象, 包括 GC Root 的直接引用, 以及由新生代中存活对象所引用的对象,触发第一次 STW 事件。这个过程是支持多线程的(JDK7 之前单线程,JDK8 之后并行,可通过参数 CMSParallelInitialMarkEnabled 调整);
      2. 并发标记(Concurrent Mark):此阶段 GC 线程和应用线程并发执行,遍历阶段 1 初始标记出来的存活对象,然后继续递归标记这些对象可达的对象;
      3. 并发预清理(Concurrent Preclean):此阶段 GC 线程和应用线程也是并发执行,因为阶段 2 是与应用线程并发执行,可能有些引用关系已经发生改变。 通过卡片标记(Card Marking),提前把老年代空间逻辑划分为相等大小的区域(Card)。如果引用关系发生改变,JVM 会将发生改变的区域标记为“脏区”(Dirty Card),然后在本阶段,这些脏区会被找出来,刷新引用关系,清除“脏区”标记;​
      4. 并发可取消的预清理(Concurrent Abortable Preclean):本阶段尝试在 STW 的最终标记阶段(Final Remark)之前尽可能地多做一些工作,以减少应用暂停时间。在该阶段不断循环处理:标记老年代的可达对象、扫描处理 Dirty Card 区域中的对象,循环的终止条件有:1、达到循环次数;2、达到循环执行时间阈值;3、新生代内存使用率达到阈值;​
      5. 最终标记(Final Remark):这是 GC 事件中第二次(也是最后一次)STW 阶段,目标是完成老年代中所有存活对象的标记。在此阶段执行:1、遍历新生代对象,重新标记;2、根据 GC Roots,重新标记;3、遍历老年代的 Dirty Card,重新标记;​
      6. 并发清除(Concurrent Sweep):此阶段与应用程序并发执行,不需要 STW 停顿,根据标记结果清除垃圾对象。清除 GC Roots 不可达对象,和用户线程一起工作,不需要暂停工作线程。由于耗时最长的并 发标记和并发清除过程中,垃圾收集线程可以和用户现在一起并发工作,所以总体上来看CMS 收集器的内存回收和用户线程是一起并发地执行;
      7. 并发重置(Concurrent Reset):此阶段与应用程序并发执行,重置 CMS 算法相关的内部数据, 为下一次 GC 循环做准备;
      5.2.3.1、常见问题
      • 最终标记阶段停顿时间过长问题:CMS 的 GC 停顿时间约 80% 都在最终标记阶段(Final Remark),若该阶段停顿时间过长,常见原因是新生代对老年代的无效引用,在上一阶段的并发可取消预清理阶段中,执行阈值时间内未完成循环,来不及触发 Young GC,清理这些无效引用。通过添加参数:-XX:+CMSScavengeBeforeRemark。但如果在上个阶段(并发可取消的预清理)已触发 Young GC,也会重复触发 Young GC。
      • 并发模式失败(concurrent mode failure):当 CMS 在执行回收时,新生代发生垃圾回收,同时老年代又没有足够的空间容纳晋升的对象时,CMS 垃圾回收就会退化成单线程的 Full GC。所有的应用线程都会被暂停,老年代中所有的无效对象都被回收。
      • 晋升失败:当新生代发生垃圾回收,老年代有足够的空间可以容纳晋升的对象,但是由于空闲空间的碎片化,导致晋升失败,此时会触发单线程且带压缩动作的 Full GC。

      并发模式失败和晋升失败都会导致长时间的停顿,常见解决思路如下:

      降低触发 CMS GC 的阈值。

      即参数 -XX:CMSInitiatingOccupancyFraction 的值,让 CMS GC 尽早执行,以保证有足够的空间。

      增加 CMS 线程数,即参数 -XX:ConcGCThreads。

      增大老年代空间。

      让对象尽量在新生代回收,避免进入老年代。

      • 内存碎片问题:通常 CMS 的 GC 过程基于标记清除算法,不带压缩动作,导致越来越多的内存碎片需要压缩。可能原因是:1、新生代 Young GC 出现新生代晋升担保失败(promotion failed));2、程序主动执行System.gc()。可通过参数 CMSFullGCsBeforeCompaction 的值,设置多少次 Full GC 触发一次压缩。默认值为 0,代表每次进入 Full GC 都会触发压缩,带压缩动作的算法为上面提到的单线程 Serial Old 算法,暂停时间(STW)时间非常长,需要尽可能减少压缩时间

      5.3、通用

      5.3.1、G1收集器

      Garbage first 垃圾收集器是目前垃圾收集器理论发展的最前沿成果,相比与 CMS 收集器,G1 收 集器两个最突出的改进是:

      1. 基于标记-整理算法,不产生内存碎片;
      2. 可以非常精确控制停顿时间,在不牺牲吞吐量前提下,实现低停顿垃圾回收。

      G1是一款面向服务器的垃圾收集器,基于基于标记-整理算法,支持新生代和老年代空间的垃圾收集,主要针对配备多核处理器及大容量内存的机器。G1 最主要的设计目标是:实现可预期及可配置的 STW 停顿时间。针对新生代和老年代,G1 提供 2 种 GC 模式,Young GC 和 Mixed GC,两种都会导致 Stop The World。G1 收集器避免全区域垃圾收集,它把堆内存划分为大小固定的几个独立区域,并且跟踪这些区域 的垃圾收集进度,同时在后台维护一个优先级列表,每次根据所允许的收集时间,优先回收垃圾最多的区域。区域划分和优先级区域回收机制,确保 G1 收集器可以在有限时间获得最高的垃圾收 集效率。执行过程如下图所示:

      jvm专题(3) - 【1/3】GC基础

      1. 初始标记(Initial Mark):暂停所有应用线程(STW),并发地进行标记从 GC Root 开始直接可达的对象(原生栈对象、全局对象、JNI 对象)。当达到触发条件时,G1 并不会立即发起并发标记周期,而是等待下一次新生代收集,利用新生代收集的 STW 时间段,完成初始标记,这种方式称为借道(Piggybacking);
      2. 根区域扫描(Root Region Scan):在初始标记暂停结束后,新生代收集也完成的对象复制到 Survivor 的工作,应用线程开始活跃起来。此时为了保证标记算法的正确性,所有新复制到 Survivor 分区的对象,需要找出哪些对象存在对老年代对象的引用,把这些对象标记成根(Root)。这个过程称为根分区扫描(Root Region Scanning),同时扫描的 Suvivor 分区也被称为根分区(Root Region)。根分区扫描必须在下一次新生代垃圾收集启动前完成(接下来并发标记的过程中,可能会被若干次新生代垃圾收集打断),因为每次 GC 会产生新的存活对象集合;
      3. 并发标记(Concurrent Marking):标记线程与应用程序线程并行执行,标记各个堆中 Region 的存活对象信息,这个步骤可能被新的 Young GC 打断。所有的标记任务必须在堆满前就完成扫描,如果并发标记耗时很长,那么有可能在并发标记过程中,又经历了几次新生代收集;
      4. 再次标记(Remark):和 CMS 类似暂停所有应用线程(STW),以完成标记过程短暂地停止应用线程, 标记在并发标记阶段发生变化的对象,和所有未被标记的存活对象,同时完成存活数据计算;
      5. 清理(Cleanup):为即将到来的转移阶段做准备, 此阶段也为下一次标记执行所有必需的整理计算工作:
      5.3.1.1、常见问题
      • Full GC 问题:G1 的正常处理流程中没有 Full GC,只有在垃圾回收处理不过来(或者主动触发)时才会出现,G1 的 Full GC 就是单线程执行的 Serial old gc,会导致非常长的 STW,是调优的重点,需要尽量避免 Full GC。

      程序主动执行 System.gc()

      全局并发标记期间老年代空间被填满(并发模式失败)

      Mixed GC 期间老年代空间被填满(晋升失败)

      Young GC 时 Survivor 空间和老年代没有足够空间容纳存活对象

      类似 CMS,常见的解决是:

      增大 -XX:ConcGCThreads=n 选项增加并发标记线程的数量,或者 STW 期间并行线程的数量:-XX:ParallelGCThreads=n。

      减小 -XX:InitiatingHeapOccupancyPercent 提前启动标记周期。

      增大预留内存 -XX:G1ReservePercent=n,默认值是 10,代表使用 10% 的堆内存为预留内存,当 Survivor 区域没有足够空间容纳新晋升对象时会尝试使用预留内存。

      • 巨型对象分配:巨型对象区中的每个 Region 中包含一个巨型对象,剩余空间不再利用,导致空间碎片化,当 G1 没有合适空间分配巨型对象时,G1 会启动串行 Full GC 来释放空间。可以通过增加 -XX:G1HeapRegionSize 来增大 Region 大小,这样一来,相当一部分的巨型对象就不再是巨型对象了,而是采用普通的分配方式。
      • 平均响应时间设置:使用应用的平均响应时间作为参考来设置 MaxGCPauseMillis,JVM 会尽量去满足该条件,可能是 90% 的请求或者更多的响应时间在这之内, 但是并不代表是所有的请求都能满足,平均响应时间设置过小会导致频繁 GC。​
      版权声明:本文内容来自第三方投稿或授权转载,原文地址:https://blog.51cto.com/arch/5276129,作者:生而为人我很遗憾,版权归原作者所有。本网站转在其作品的目的在于传递更多信息,不拥有版权,亦不承担相应法律责任。如因作品内容、版权等问题需要同本网站联系,请发邮件至ctyunbbs@chinatelecom.cn沟通。

      上一篇:Zookeeper(4) - 会话管理和事务处理

      下一篇:MongoDB-索引

      相关文章

      2025-04-14 08:45:56

      java学习第十一天笔记-字符串222-学生管理系统4查询

      java学习第十一天笔记-字符串222-学生管理系统4查询

      2025-04-14 08:45:56
      i++ , java , jvm , System , 学习
      2025-04-01 10:28:48

      java中satb和tlab有什么区别?

      java中satb和tlab有什么区别?

      2025-04-01 10:28:48
      Java , jvm , JVM , 内存空间
      2025-03-17 07:49:59

      jvm内存堆栈监控之jmap篇

      jvm内存堆栈监控之jmap篇

      2025-03-17 07:49:59
      heap , jvm , 内存
      2025-03-11 09:34:18

      【java虚拟机】JVM知识框架快速一览

      【java虚拟机】JVM知识框架快速一览

      2025-03-11 09:34:18
      GC , JVM , 内存 , 对象 , 方法
      2025-03-04 09:11:34

      查看rancher中debug端口信息,并做IDEA Remote Jvm Debug

      查看rancher中debug端口信息,并做IDEA Remote Jvm Debug

      2025-03-04 09:11:34
      debug , Debug , IDEA , jvm , 断点
      2025-01-16 09:30:08

      java基础(1)

      java基础(1)

      2025-01-16 09:30:08
      java , JAVA , jsp , jvm , php , 动态 , 客户端
      2024-12-16 09:17:45

      JVM体系结构的详细阐述

      JVM体系结构的详细阐述

      2024-12-16 09:17:45
      GC , Java , 内存 , 加载 , 方法
      2024-10-25 07:15:55

      Java服务端性能优化:JVM垃圾回收策略

      Java 虚拟机(JVM)是 Java 程序运行的基础,而垃圾回收(GC)是 JVM 管理内存的核心机制之一。垃圾回收策略的选择和优化对 Java 服务端性能有着直接的影响。本文将探讨 JVM 垃圾回收的基本原理,介绍几种常见的垃圾回收策略,并提供一些优化建议。

      2024-10-25 07:15:55
      GC , 回收 , 垃圾
      2024-09-25 10:15:15

      jvm专题(4) - 【1/3】多线程-基础知识

      jvm专题(4) - 【1/3】多线程-基础知识

      2024-09-25 10:15:15
      jvm , 多线程
      2024-09-25 10:14:48

      JOL学习

      JOL(Java Object Layout)是一个开源的 Java 库,用于深入了解和分析 Java 对象的内存布局。它提供了一组工具和API,可以用于查看对象的内部结构、字段排列顺序、内存对齐等信息,以及计算对象的大小和对齐方式。

      2024-09-25 10:14:48
      java , jvm , 学习
      查看更多
      推荐标签

      作者介绍

      天翼云小翼
      天翼云用户

      文章

      33561

      阅读量

      5265331

      查看更多

      最新文章

      查看rancher中debug端口信息,并做IDEA Remote Jvm Debug

      2025-03-04 09:11:34

      JOL学习

      2024-09-25 10:14:48

      java swing中的卡片布局

      2024-09-25 10:13:34

      【java基础】泛型的通配符(extends,super,?)

      2024-09-24 06:30:37

      KVM和JVM的虚拟化技术有何区别?

      2024-06-07 07:41:34

      聊聊指令重排序

      2024-06-07 07:39:41

      查看更多

      热门文章

      GC是什么? 为什么要有GC?

      2023-05-10 06:02:16

      java学习第一天笔记-java基础概念01-注释17

      2023-03-08 10:52:50

      java学习第一天笔记-java基础概念04-字面量2-基本用法21

      2023-03-14 09:34:35

      全网详细解决java.lang.ClassCastException: xxx类型 cannot be cast to xxx类型

      2023-07-11 08:45:04

      【java基础】抽象类和抽象方法

      2023-07-03 08:06:20

      【java基础】泛型的限制及其继承规则

      2023-07-03 08:06:07

      查看更多

      热门标签

      linux java python javascript 数组 前端 docker Linux vue 函数 shell git 节点 容器 示例
      查看更多

      相关产品

      弹性云主机

      随时自助获取、弹性伸缩的云服务器资源

      天翼云电脑(公众版)

      便捷、安全、高效的云电脑服务

      对象存储

      高品质、低成本的云上存储服务

      云硬盘

      为云上计算资源提供持久性块存储

      查看更多

      随机文章

      JUC概述

      【java基础】抽象类和抽象方法

      jvm

      jvm(3)

      【java基础】多态、编译类型、运行类型、强制类型转换、动态绑定关系梳理

      【java基础】一篇文章彻底搞懂java反射

      • 7*24小时售后
      • 无忧退款
      • 免费备案
      • 专家服务
      售前咨询热线
      400-810-9889转1
      关注天翼云
      • 旗舰店
      • 天翼云APP
      • 天翼云微信公众号
      服务与支持
      • 备案中心
      • 售前咨询
      • 智能客服
      • 自助服务
      • 工单管理
      • 客户公告
      • 涉诈举报
      账户管理
      • 管理中心
      • 订单管理
      • 余额管理
      • 发票管理
      • 充值汇款
      • 续费管理
      快速入口
      • 天翼云旗舰店
      • 文档中心
      • 最新活动
      • 免费试用
      • 信任中心
      • 天翼云学堂
      云网生态
      • 甄选商城
      • 渠道合作
      • 云市场合作
      了解天翼云
      • 关于天翼云
      • 天翼云APP
      • 服务案例
      • 新闻资讯
      • 联系我们
      热门产品
      • 云电脑
      • 弹性云主机
      • 云电脑政企版
      • 天翼云手机
      • 云数据库
      • 对象存储
      • 云硬盘
      • Web应用防火墙
      • 服务器安全卫士
      • CDN加速
      热门推荐
      • 云服务备份
      • 边缘安全加速平台
      • 全站加速
      • 安全加速
      • 云服务器
      • 云主机
      • 智能边缘云
      • 应用编排服务
      • 微服务引擎
      • 共享流量包
      更多推荐
      • web应用防火墙
      • 密钥管理
      • 等保咨询
      • 安全专区
      • 应用运维管理
      • 云日志服务
      • 文档数据库服务
      • 云搜索服务
      • 数据湖探索
      • 数据仓库服务
      友情链接
      • 中国电信集团
      • 189邮箱
      • 天翼企业云盘
      • 天翼云盘
      ©2025 天翼云科技有限公司版权所有 增值电信业务经营许可证A2.B1.B2-20090001
      公司地址:北京市东城区青龙胡同甲1号、3号2幢2层205-32室
      • 用户协议
      • 隐私政策
      • 个人信息保护
      • 法律声明
      备案 京公网安备11010802043424号 京ICP备 2021034386号