今天给各位分享微乐辅助神器开挂教程的知识,其中也会对微乐挂先试用后付款进行解释,如果能碰巧解决你现在面临的问题,别忘了关注本站,现在开始吧!棋牌抓包可...
2025-06-08 0
背景
7 月份的时候,由于发现集团已经提供 JDK11 的流水线升级,可以通过流水线快速升级 JDK11,并解决相关的依赖问题。于是我欢天喜地地升级了 JDK11,在预发经过测试后没有问题后,顺利发布上线,GC 次数有了明显下降。
故障出现
线上稳定运行了半个月,突然开始触发告警,内存利用率超过 85%。一看监控,发现出现了几个现象。
1.内存利用率不断升高,提升到 85%,一天内没有下降。
2.G1 Old GC 不断升高,没有进行回收。
当时我设置的 JVM 参数非常简单,只保留了 CMS 的堆内存设置,最大最小堆内存都是 12G。
-Xms12g -Xmx12g
通过 jmap 查看 heap 情况(jhsdb jmap --heap --pid 185579):
临时解决方案
1.保留一台 beta 环境机器进行观察,其他环境机器批量重启。
2.重启机器后,内存利用率下降,因此初步认定,造成告警的原因是 G1_OLD 区未触发回收。
beta 机器在未重启的情况下,内存使用率不断提高,最后超过 90%(这也是本文标题由来)。
最终解决方案
经过查询资料之后,最后的解决方案就是调整 JVM 参数,将堆内存缩减到8G,问题解决。
简单结论:一般8G容器的堆内存建议设置4G,16G容器堆内存建议设置8G。
那么从 JDK8 升级到 JDK11 之后,发生了什么呢?为什么同样的参数在 CMS 上一点问题没有,上到 G1GC 之后却有这样的问题呢?接下来我们好好介绍 G1GC。
从 GC 开始
内存中创建对象时发生了什么?
Java 最核心的一点特性就是它的内存管理机制。要聊 GC,我们先从内存分配开始。每个 Java 对象都需要在内存中有一个空间,用于保存它的数据和引用关系。那么创建对象时,怎么在内存中划出一份空间给对象呢?最直觉的方法跟数组的使用是一致的。把内存认为是一个数组,用一个内存指针作为索引指向当前空闲空间的开头,当需要为对象分配空间时,由于对象的大小是确定的,因此可以直接把指针后面的空间直接分给当前对象,只需要将指针移动指定大小的位置即可完成分配。这种方式就叫做指针碰撞。
指针碰撞:它通过维护一个指针,指向空闲内存的起始位置。当需要分配内存时,只需将该指针向前移动所需内存大小的距离即可。
通过这种技术进行内存分配后,当出现对象被回收的情况时,因为指针只有一个,因此无法把前面回收的部分进行再次分配,它只能继续往后分配。因此又出现了一种新的技术。空闲列表技术。它的本质正如它的名字一样,使用一个列表来记录内存中的空闲位置,每次分配对象时,就会查找这个列表,找到一块大小可以分配当前对象的空闲空间,然后把对象放到这块空间里,再从空闲列表中把这块空闲区域去掉。
空闲列表:它维护一个列表,记录所有可用的内存块信息。当需要分配内存时,从列表中查找合适大小的空闲块进行分配。
以上两种技术,遇到多线程时要怎么处理呢?对于指针碰撞这种方案,最简单的方式就是给每个线程划分一个空间,每个线程在自己的空间中进行内存分配,这样就不会发生冲突。这也就是 JVM 中 TLAB 的由来,(Thread Local Allocation Buffer)线程本地分配缓存区,每次 GC 结束后,每个线程都会申请一块 TLAB 进行内存分配,当 TLAB 申请不到时,线程会尝试在 Eden 区分配,若 Eden 也不足,则可能触发 Young GC。
而对于空闲列表,多线程的分配方案就是乐观锁机制,也就是CAS+失败重试。
TLAB (Thread Local Allocation Buffer):线程本地分配缓存区,每次 GC 结束后,每个线程都会申请一块 TLAB 进行内存分配。
内存回收
内存回收的算法
只有了解了内存的分配方式,我们才能更加深刻地理解内存回收的方案。针对前面我们说的两种内存分配方式,我们可以提出以下这些内存回收的方案。
1.标记-清除算法:标记出使用的对象,然后将没有标记的对象清理。
2.标记-复制算法:为了解决面对大量可回收对象时,清理时间增加的情况。出现了一种半区复制的算法。也就是将内存分成两部分,每次使用其中一部分,回收时,将少量剩余的存活对象按顺序复制到另一部分。
3.标记-整理:这个跟标记-复制有点像,核心差异点是,标记复制的对象移动是在两个区来回移动的。而标记整理只会往内存的一端移动。
分代回收
分代回收,是指将内存区域分为新生代和老年代,不同代使用不同的回收手段。而这个分代回收是建立在两条原则上的
1.绝大多数对象都是朝生夕死的。
2.熬过越多次垃圾收集过程的对象就越难以消亡。
如果一个区域中大多数对象都是朝生夕灭,难以熬过垃圾收集过程的话,那么把它们集中放在一起,每次回收时只关注如何保留少量存活而不是去标记那些大量将要被回收的对象,就能以较低代价回收到大量的空,因此使用标记-复制算法。
对于老年代的对象,由于他们难以使用消亡,频繁的挪动成本非常的高,使用空闲列表的方式进行内存的分配和回收往往是性价比更高的方案。
CMS 回收就是使用标记清除算法,标记垃圾,然后清除,再使用空闲列表记录空闲区域。但是这样,当内存碎片很多时,会存在总体空闲内存足够多,但是却不能给对象分配空间的情况。这个时候,CMS 就会使用标记-整理算法,进行一次内存空间整理。
高吞吐和低延迟不能兼得
高吞吐是指GC系统在单位时间内能够处理的内存回收量。
低延迟是指垃圾回收过程中应用程序暂停的时间尽可能短。在低延迟的GC策略下,系统会尽量减少每次垃圾回收操作的停顿时间,即减少应用程序因等待GC完成而停止响应的时间。
高吞吐和低延迟之间存在一种权衡关系。通常情况下,为了实现高吞吐,GC可能会采取一些策略,比如增加垃圾回收的频率或者扩大垃圾回收的范围,这可能会导致每次垃圾回收的时间变长,从而增加了延迟。
相反,为了实现低延迟,GC可能会采取减少每次垃圾回收的范围或者优化垃圾回收算法来减少停顿时间,但这可能会增加垃圾回收的总次数,从而降低了吞吐量。
GC 策略转变
回顾内存管理技术的发展历程,GC 策略的演进呈现出明显的方向性转变:从追求高吞吐量逐步转向对低延迟的优化,以适配现代互联网服务的性能要求。早期的垃圾收集算法以提升系统吞吐量为首要目标,其设计理念导致在极端场景下可能产生较高的延迟波动。随着Java语言在互联网服务领域的广泛应用,加之硬件成本下降带来的内存容量提升,系统架构逐渐能够承载更频繁的垃圾回收操作,以此换取更稳定的服务响应。
这一技术演变路径在主流垃圾收集器的迭代中清晰可见:从采用并发标记清除(CMS)机制,到引入分代式收集器(G1),直至实现亚毫秒级停顿的ZGC无停顿收集器,每一种 GC 机制的出现都标志着对对延迟控制的进一步优化。
CMS
CMS(Concurrent Mark Sweep)垃圾收集器是第一个关注 GC 停顿时间(STW 的时间)的垃圾收集器。
MS 就是 mark-sweep 的缩写,即标记-清除算法。
CMS 垃圾收集器之所以能够实现对 GC 停顿时间的控制,其本质来源于对「可达性分析算法」的改进,即三色标记算法。在 CMS 出现之前,它们在进行垃圾回收的时候都需要 Stop the World,无法实现垃圾回收线程与用户线程的并发执行。而 CMS 将整个回收过程分为了四步,在最耗时的标记和清除阶段都可以跟用户线程并行执行,这也是为什么它延迟低的原因。
G1GC 介绍
G1GC 最大的特征是非常重视实时性,G1GC 的实时性是软实时性,即处理多用于稍微超出几次最后期限也没什么问题的系统中,例如网络银行系统。用户总会期待所有的交易都能完美地处理好,但是稍微超出几次最后期限,比如交易完成界面的展示慢了一些,应该也不会构成致命的问题。
为了实现软实时性,它具备以下两个功能。
1.设置期望暂停时间(最后期限)
2.可预测性
G1 如何实现可预测性
G1 会分步并行进行空间回收。G1 通过跟踪先前应用行为和垃圾收集暂停的信息,建立相关成本模型,从而实现可预测性。它利用这些信息来确定暂停期间的工作量。
分区
G1 的老年代和年轻代不再是一块连续的空间,整个堆被划分成若干个大小相同的 Region,也就是区。
Region 的类型有 Eden、Survivor、Old、Humongous 四种,而且每个 Region 都可以单独进行管理。
Humongous 是用来存放大对象的,如果一个对象的大小大于一个 Region 的 50%(默认值),那么我们就认为这个对象是一个大对象。为了防止大对象的频繁拷贝,我们可以将大对象直接放到 Humongous 中。
回收的实际过程
G1 回收的实际过程可以概括为一个循环,以下的官方文档的介绍。
On a high level, the G1 collector alternates between two phases. The young-only phase contains garbage collections that fill up the currently available memory with objects in the old generation gradually. The space-reclamation phase is where G1 reclaims space in the old generation incrementally, in addition to handling the young generation. Then the cycle restarts with a young-only phase.
翻译:在高层次上,G1收集器在两个阶段之间交替进行。young only 阶段包含了垃圾收集,这些收集逐渐用老年代中的对象填满当前可用的内存。space-reclamation (空间回收)阶段是G1在处理年轻代的同时,逐步回收老年代的空间。然后,周期以young only 阶段重新开始。
怎么理解这段话?
1.G1收集器的两个主要阶段:
2.仅年轻代阶段(Young-only phase):
3.空间回收阶段(Space-reclamation phase):
4.循环过程:
三个阶段的介绍:
1.并发开始(Concurrent Start):
2.重新标记(Remark):
3.清理(Cleanup):
4.总结:
仅年轻代阶段(Young-only Phase)主要进行 Minor GC(Young GC),不断将存活对象晋升到老年代。当老年代占用率超过IHOP阈值时,G1 触发并发开始 GC(Concurrent Start GC),启动并发标记(Concurrent Marking),用于检测老年代中的存活对象。并发标记完成后,G1 进入STW 的重新标记(Remark)和清理(Cleanup)阶段,最终决定是否进入Mixed GC(空间回收阶段)。如果老年代回收效率足够高,G1 进入Mixed GC,否则继续 Young GC。
混合回收(Mixed Collections, Mixed GC):这个阶段,G1不仅清理年轻代,还会增量回收部分老年代,以防止老年代占用率过高导致 Full GC。
这里的关键点是“混合”:
1.继续执行年轻代 GC(Minor GC)。
2.选取部分老年代 Region进行存活对象疏散(Evacuation),将存活对象复制到其他 Region,然后回收已清理的 Region。这样,G1避免了 CMS 那种碎片化问题,确保老年代的可用空间更整齐。
具体流程:
1.Mixed GC 如何进行:
2.结束条件:
3.循环重启:
空间回收阶段(Mixed GC)结束后,G1 重新进入 Young-only 阶段。
这个过程不断循环:Young-only Phase(仅年轻代阶段) → Space-reclamation Phase(空间回收阶段) → Young-only Phase
如果 Mixed GC 不能及时回收足够的老年代空间,并且应用程序继续分配对象导致堆空间耗尽,G1 会触发 Full GC(STW 进行全堆压缩整理)。Full GC 代价极高,一般是 G1 最不希望发生的情况。
4.总结:
空间回收阶段(Space-reclamation Phase)主要通过Mixed GC(混合回收)逐步回收老年代。G1 选择部分老年代 Region,将存活对象疏散到其他区域后释放这些 Region,从而避免碎片化。Mixed GC 会持续进行,直到回收效率下降到设定阈值,之后进入新的 Young-only 阶段。如果在这个过程中应用程序分配过快,G1 无法及时回收足够的空间,就会触发代价极高的Full GC。
G1 中的 GC 类型
G1 GC中涉及的几种GC包括:
1.Young GC(新生代回收):
Young GC主要负责回收新生代中的对象。新生代包含新创建的对象,这些对象更有可能在短时间内变成垃圾。Young GC执行过程相对较快,因为它只涉及新生代中对象的扫描和回收。在Young GC过程中,Eden区和Survivor区的存活对象会被复制到另一个Survivor区或者晋升到老年代。这个过程是Stop-The-World(STW)的,意味着在回收过程中,应用程序的所有线程都会被暂停。
年轻代GC会选择所有的年轻代区域加入回收集合中,但是为了满足用户停顿时间的配置,在每次GC后会调整这个最大年轻代区域的数量,每次回收的区域数量可能是变化的,换言之,young 区的大小是会动态调整的。
2.Mixed GC(混合回收):
Mixed GC是G1收集器特有的回收策略,它不仅回收新生代中的所有Region,还会回收部分老年代中的Region。这种策略的目标是在保证停顿时间不超过预期的情况下,尽可能地回收更多的垃圾对象。在Mixed GC过程中,首先会进行全局并发标记(global concurrent marking),这个过程是并发的,与应用程序线程同时执行,用于标记出所有存活的对象。然后,在回收阶段,G1会根据标记结果选择收益较高的部分老年代Region和新生代Region一起进行回收。这个选择过程是基于对Region中垃圾对象的数量和回收价值的评估。
3.Full GC:
Full GC是指对整个Java堆(包括年轻代、老年代和元空间)的垃圾回收。在G1中,通常尽量避免Full GC的发生,因为Full GC会导致较长时间的停顿。G1通过Mixed GC来回收部分老年代的Region,以减少Full GC的需要。但如果Mixed GC无法跟上内存分配的速度,导致老年代空间不足,或者在某些特殊情况下,比如巨型对象分配失败时,就会触发Full GC。G1中的Full GC使用的是Serial Old GC的代码,这意味着它会暂停所有应用线程,并执行效率相对较慢的单线程垃圾回收。它是原地(in-place)进行的,意味着在同一内存空间内移动和压缩对象。
总结:G1 GC通过Young GC和Mixed GC来优化垃圾回收性能,减少停顿时间,而Full GC是作为最后的手段,在必要时对整个堆进行回收。
与 CMS 进行对比
CMS垃圾回收器是第一个并发垃圾回收器。像其他算法一样,CMS使用多个线程来执行回收操作。CMS垃圾回收器自JDK 11被正式废弃,而且不鼓励在JDK 8中使用。从实际的角度来看,由于CMS使用的是标记-清除算法,导致它不能在后台处理过程中压缩堆。如果堆变得碎片化,那么CMS必须停止所有的应用程序线程并压缩堆,也就是执行标记-整理算法,这就违背了使用并发垃圾回收器的初衷。因为这个原因,并且 G1 GC 具备自动整理堆内存的能力,减少了碎片问题,因此官方推荐使用 G1 GC 替代 CMS。
性能提升
整体而言 JDK11 优于 JDK8,G1 优于 CMS。在两个 JDK 版本默认状态下(JDK11 + G1 V.S JDK8 + CMS),JDK11 max-jOPS 分数提升 17%,critical-jOPS 分数提升 105%
GC | 运行 SPECJbb2015 性能分析 | |||
YGC平均暂停时间 | 吞吐量 | max-jOPS (纯吞吐量) | critical-jOPS (限制响应时间下的吞吐量) | |
JDK8+CMS(基线数据) | 311ms | 92.7% | 15706 | 3898 |
JDK8+G1 | 187ms | 94.7% | 17098 | 5338 |
JDK11+CMS | 274ms | 94.2% | 15905 | 4821 |
JDK11+G1 | 177ms (↓43%) | 94.7%(↑2pt) | 18376 (↑17%) | 7980(↑105%) |
数据来自:AArch64版JDK8/11性能分析
内存使用率增加的复盘
内存分配原理
物理内存指的是PSS或RSS, 包括堆内的物理内存和堆外的, 小于等于预留的内存. 物理内存的分配方式通常是按需分配, 也就是只有写入虚拟内存的时候,内核才进行物理内存分配 (又叫touch)。读取虚拟内存或者预留 (mmap) 虚拟内存, 进程当时都不会产生物理内存。
换言之,通过JVM的参数-Xmx和-Xms可以设置JVM的堆大小,但是此时操作系统分配的只是虚拟内存,只有JVM真正要使用该内存时,才会被分配物理内存。
内存分配过程
1.对象首先会先分配在年轻代,因为之前分配的只是虚拟内存,所以每次新建对象都需要操作系统来先分配物理内存,只有等第一次新生代GC后,该被分配的内存空间都已经分配了,之后分配对象的速度才会加快。
2.那么老年代也是同理,老年代的空间何时真正使用,自然是对象需要晋升到老年代时,所以新生代GC的时候,对象要从新生代晋升到老年代,操作系统也需要为老年代先分配物理内存。
为什么升级后内存占用率提升
G1老区占用比CMS多, 原因是
1.CMS 采用的是 按地址顺序分配老年代内存,并且固定老年代的回收阈值。在低负载下,老年代内存的某些区域可能长时间不会被触及,造成碎片化,直到内存压力较高时才开始回收。
2.G1 GC使用Region-based 分配策略,这种策略采用了启发式算法,尝试尽量填满堆内存,避免老年代有空闲区域而造成内存浪费。因此,G1 的区域分配比 CMS 更加灵活,它会自动调整阈值并较快touch所有堆内存。
CMS 中有一个结构叫 card table,卡表,它是一种记录老年代对新生代引用的机制,卡表是为了解决了在新生代垃圾收集时,如何快速找到老年代中引用新生代对象的问题。它的工作原理:将老年代内存空间划分为固定大小的卡页。使用一个字节数组(卡表)来标记每个卡页的状态。如果一个卡页中的对象可能引用了新生代对象,该卡页就被标记为"脏"。在进行新生代垃圾收集时,只需要扫描被标记为脏的卡页,而不是整个老年代。
像 G1 这种分区回收算法,有些 Region 可能被选入 CSet,有些则不会。所以,我们需要知道当一个 Region 需要被回收时,有哪些其他的 Region 引用了自己。相应地,为了加快定位速度,分区回收算法为每个 Region 都引入了记录集(Remembered Set,RSet),每个 Region 都有自己的专属 RSet。和 Card table 不同的是,RSet 记录谁引用了我,这种记录集被人们称为 point-in 型的,而 Card table 则记录我引用了谁,这种记录集被称为 point-out 型。
1.不需要记录的引用:
2.需要记录的引用:
3.记录引用的方式:通过写屏障(Write Barrier)机制,当对象A在Region1中引用对象B在Region2时,这个引用信息(称为“dirty card”)会被添加到Region2的RSet中。在 G1 中,我们把这种 card 称为 dirty card。业务线程也不是直接将 dirty card 放到 RSet 中的。而是在业务线程中引入一个叫做 dirty card queue(DCQ)的队列,在写屏障中,业务线程只需要将 dirty card 放入 DCQ 中。接下来, G1 GC 中的 Refine 线程,会从 DCQ 中找到这种 dirty card,然后再去做更精细的检查,只有确实不属于上面所描述的三种情况的跨区引用,才真正放到专属 RSet 中去。
值得一提的是,Java 一直在尝试优化记忆集的占用,下图是 P99 CONF-G1:To Infinity and Beyond 的一个对比,在 16G 的堆内存情况下,高版本的的 JDK 的记忆集大小有了明显的改善。
总结
1.由于设置了 12G 的堆内存,且 G1 修改了内存管理方式,导致 G1 能够占用满这 12G 的堆内存,而 CMS 由于有固定old区回收阈值, 如果低压力下, old区末尾的部分内存几乎永远不会被用到,因此即使分配了 12G 内存也不会真正占用 12G 内存。
2.JDK11 下的 G1 的记忆集占用了较大的空间。
因此,12g 堆内存+2.25g记忆集+700m 的全局内存+非堆内存 ≈ 16g,这也是为什么最后能升到 95% 以上的原因。
几种解决方案
如果想要避免内存逐渐增加并导致突发的延迟,JVM 提供了-XX:+AlwaysPreTouch 参数。该参数能够在服务启动时预先将虚拟内存映射为物理内存,避免后续因按需分配物理内存而导致的延迟。这样可以提高程序在运行时的内存分配效率,避免由于内存分配引起的卡顿或停顿。但它的缺点是会显著增加 JVM 启动时间,毕竟把分配物理内存的事提前放到JVM进程启动时做了,尤其是在内存较大的情况下,启动时间可能会大幅增加。
虽然在 G1 下老年代内存使用较高,但通常不会引发 OOM(内存溢出)风险,因为即使在长时间运行中,G1 也会调整回收策略以避免内存溢出。如果内存使用率已经达到警戒线,建议适当缩小堆大小。通常认为在 JDK11中,对于许多 Java 应用而言,堆内存占总内存的一半是比较合适的选择。
G1GC参数调优
CMS切换成G1的参数替换
CMS原参数 | G1替换参数 (加粗为必改, 否则选改) | 解释 |
-Xms10g -Xmx10g | -Xms10g -Xmx10g 或 -Xms9500m -Xmx9500m | G1堆外内存稍高, 且使用region-based的管理算法, 导致footprint稍高, 为了不出现意外容器OOM, 适当降低5-8%的堆大小 比如buy2本来内存已经到82%了, 再高就要破90%了, 需要调小以应对风险 注: 内存水线是视业务行为而定的, 比如ump2不用调堆, 也可以保持原来的水线 注2: 这个幅度调小堆一般不会导致Java OOM, 因为G1对Survivor区的利用率比CMS高不少, 碎片化风险也比CMS低 |
-Xmn6g | -XX:MaxNewSize=6g | 把-Xmn替换成-XX:MaxNewSize即可, 数字不变 也可以省略这个参数, 因为默认MaxNewSize就是60%, 所以相当于10g x 60% = 6g, 但是必须要记得把Xmn删掉 总之G1需要灵活调整Young区, 所以G1不要设置Xmn |
-XX:G1HeapRegionSize=32m | G1跟CMS的一个巨大差别就是他用region-based的管理算法, 超过region大小的一半会当成"大对象", 大对象太多了有损性能,原因是 G1 对于大对象的处理非常消极,基本上不会怎么处理 | |
-XX:+CMSScavengeBeforeRemark -XX:+UseConcMarkSweepGC -XX:CMSMaxAbortablePrecleanTime=5000 -XX:+CMSClassUnloadingEnabled | -XX:+UseG1GC | CMS相关参数, 不需要 |
-XX:CMSInitiatingOccupancyFraction=80 -XX:+UseCMSInitiatingOccupancyOnly | -XX:InitiatingHeapOccupancyPercent=40 -XX:-G1UseAdaptiveIHOP | 控制Old区大小, 比如原来CMS大约在 (0.8*(10g-6g)=3277m) 触发Old区GC, G1配置成在 (0.4*9500=3800m) 触发 因为G1会把大对象也往老区放, 所以我们会倾向于把这个设置得比CMS高一点 |
-XX:G1HeapWastePercent=2 | G1默认会接受5%的"浪费", 把他减少到2%, 可以大约挤出200-300m的空间, 当然这个是有代价的, G1回收成本会变高, 视情况加 |
推荐参数介绍
let JVM_HEAP = "-Xms8g -Xmx8g -XX:MetaspaceSize=1024m -XX:MaxMetaspaceSize=1024m -XX:ReservedCodeCacheSize=512m -XX:MaxDirectMemorySize=512m"let JVM_GC = "-XX:+UseG1GC -XX:G1HeapRegionSize=16m -XX:InitiatingHeapOccupancyPercent=40 -XX:-G1UseAdaptiveIHOP -XX:+ExplicitGCInvokesConcurrent -XX:ParallelGCThreads=8 -Dio.netty.tryReflectionSetAccessible=true --add-opens=java.base/jdk.internal.misc=ALL-UNNAMED --add-opens=java.base/java.nio=ALL-UNNAMED"
-XX:MaxGCPauseMillis
设置期望的最大GC停顿时间指标,G1收集器会尽力在这个时间内完成垃圾回收,以减少应用程序的停顿时间。默认值是200毫秒,调整这个参数可以影响GC的停顿时间
无论是 young GC 还是 mixed GC,都会回收全部的年轻代,因此这个参数如果设置得太短,会限制 young 区占用的 region数量,可能会导致G1跟不上垃圾产生的速度,最终退化成Full GC。
作用:
定义:MaxDirectMemorySize 指定了 JVM 可以分配的最大直接内存大小。
直接内存(Direct Memory):
默认值:如果不指定,默认值通常等于 -Xmx(最大堆大小)。
设置每个Region的大小,G1的目标是根据最小的Java堆大小划分出约2048个这样的区域。这个值必须是2的幂,范围在1MB到32MB之间。默认情况下,这个值是堆内存的1/2000,这意味着G1收集器管理的最小堆内存应该是2GB以上,最大堆内存为64GB。调整这个参数可以影响G1的内存管理效率和垃圾回收的性能。
用于控制显式垃圾回收(Explicit GC)调用的行为。当这个参数被启用时,它会使得通过 System.gc() 或者其他形式的显式垃圾回收请求触发并发(concurrent)的垃圾回收操作,而不是完全停止(full stop-the-world)的应用程序线程进行垃圾回收。
1.定义:-XX:ParallelGCThreads 用于设置并行垃圾收集器的线程数。这些线程用于执行 Stop-The-World(STW)垃圾收集阶段。
2.默认值:
分别用于设置新生代最小和最大容量的百分比。这两个参数可以控制新生代的大小,影响垃圾收集的频率和性能。一般不推荐修改。
The Initiating Heap Occupancy Percent (IHOP) is the threshold at which an Initial Mark collection is triggered and it is defined as a percentage of the old generation size.
G1 by default automatically determines an optimal IHOP by observing how long marking takes and how much memory is typically allocated in the old generation during marking cycles. This feature is called Adaptive IHOP. If this feature is active, then the option -XX:InitiatingHeapOccupancyPercent determines the initial value as a percentage of the size of the current old generation as long as there aren't enough observations to make a good prediction of the Initiating Heap Occupancy threshold. Turn off this behavior of G1 using the option-XX:-G1UseAdaptiveIHOP. In this case, the value of -XX:InitiatingHeapOccupancyPercent always determines this threshold.
Internally, Adaptive IHOP tries to set the Initiating Heap Occupancy so that the first mixed garbage collection of the space-reclamation phase starts when the old generation occupancy is at a current maximum old generation size minus the value of -XX:G1HeapReservePercent as the extra buffer.
翻译:初始堆占用百分比(IHOP)是触发初始标记收集的阈值,它被定义为老年代大小的百分比。
G1默认会通过观察标记过程所需的时间以及在标记周期期间通常在老年代中分配的内存量来自动确定最佳的IHOP。这个特性被称为自适应IHOP。如果这个特性是激活的,那么 -XX:InitiatingHeapOccupancyPercent 选项会决定初始值,作为当前老年代大小的百分比,这种情况会持续到有足够的观察数据来做出良好的初始堆占用阈值预测为止。使用 -XX:-G1UseAdaptiveIHOP 选项可以关闭G1的这种行为。在这种情况下,-XX:InitiatingHeapOccupancyPercent 的值将始终决定这个阈值。
在内部,自适应IHOP试图设置初始堆占用,使得空间回收阶段的第一次混合垃圾收集在老年代占用达到当前最大老年代大小减去 -XX:G1HeapReservePercent 值作为额外缓冲区时开始。
1.自适应IHOP:
2.-XX:InitiatingHeapOccupancyPercent:
3.禁用自适应IHOP:
4.自适应IHOP的内部工作:
这个参数指定触发在老年代的内存空间达到一定百分比之后,启动并发标记。默认值是 45%,当然,这更进一步是为了触发 mixed GC,以此来回收老年代。如果一个应用老年代对象产生速度较快,可以尝试适当调小 IHOP。
1.并发标记的目的:
2.G1 收集器的工作流程:
UseAdaptiveIHOP 是 G1 垃圾收集器的一个功能,它根据堆内存晋升速率自动调节 IHOP(Initiating Heap Occupancy Percent)。IHOP 决定了触发并发标记周期的堆占用阈值。使用 -XX:-G1UseAdaptiveIHOP 参数可以禁用这个自动调节功能,此时 IHOP 值将固定为初始设置,通常由 -XX:InitiatingHeapOccupancyPercent 参数指定。这种做法类似于使用 -Xmn 参数固定年轻代大小。
关于是否应该禁用 UseAdaptiveIHOP,存在不同观点。有建议关闭此功能以防止频繁的并发 GC,而另一种观点认为除非 G1 的自动调节表现不佳,否则不应更改。
我的看法是,如果应用程序在默认设置下表现良好,就保持 UseAdaptiveIHOP 启用。只有在遇到明确的性能问题时,才考虑禁用它。在做出任何更改之前,最好先收集详细的 GC 日志进行分析,然后根据分析结果决定是否需要调整。需要注意的是,更改 IHOP 设置可能会影响 GC 的频率和停顿时间,因此调整后需要进行充分的测试和监控。
1.参数定义:-XX:G1HeapWastePercent 设置了 G1 垃圾收集器在停止回收之前允许的堆内存浪费百分比。
2.默认值:默认值是 5%,意味着 G1 允许最多 5% 的堆内存被浪费(即未被使用)。
3.参数作用:
4.工作原理:
5.调优考虑:
6.使用场景:
-Dio.netty.tryReflectionSetAccessible=true --add-opens=java.base/jdk.internal.misc=ALL-UNNAMED --add-opens=java.base/java.nio=ALL-UNNAMED
必须设置,解决堆外内存增加 600M 的问题。
相关文章
今天给各位分享微乐辅助神器开挂教程的知识,其中也会对微乐挂先试用后付款进行解释,如果能碰巧解决你现在面临的问题,别忘了关注本站,现在开始吧!棋牌抓包可...
2025-06-08 0
本篇文章给大家谈谈微信打麻将小程序有挂吗,以及微信小程序麻将有挂吗怎么赢对应的知识点,希望对各位有所帮助,不要忘了收藏本站喔。 微信小程序打麻将会被涉...
2025-06-08 0
6月7日凌晨,腾讯官方公众号发布消息表示,QQ昵称为“爱芥末”的用户,成为了全球拥有“时光企鹅”等级图标的第一人。据悉,这是全球首位QQ 256级用户...
2025-06-07 0
据Wccftech 报道,GPU 大厂英伟达 (NVIDIA) 首席科学家 Bill Dally 指出,华为 (Huawei) 正从英伟达在中国的业务...
2025-06-07 0
今年上半年最重要的促销大战“618”正在火热进行但部分地方却传出家电以旧换新“国补”暂停或者调整的消息近日,“重庆国补暂停”等相关消息在社交媒体平台上...
2025-06-07 0
九派新闻 6月7日凌晨,腾讯官方公众号发布消息表示,QQ昵称为“爱芥末”的用户,成为了全球拥有“时光企鹅”等级图标的第一人。据悉,这是全球首位QQ 2...
2025-06-07 0
在微信早已成为国民级社交应用的今天,你还在用QQ吗?又是否记得曾让很多年轻人彻夜挂机来升等级的日子?就在今天凌晨,全球首位256级QQ用户诞生,解锁“...
2025-06-07 0
6月7日凌晨,腾讯发布消息称,QQ昵称为“爱芥末”的用户,成为了全球拥有“时光企鹅”等级图标的第一人。据悉,在6月7日0点56 分,“爱芥末” 的QQ...
2025-06-07 0
发表评论