你有效地管理 JVM 的垃圾了吗?是时候把垃圾拿出来了!
2.正常删除(Normal Deletion)
正常删除是指移除未引用的对象,留下引用的对象和指向空闲空间的指针。
3.压缩删除(Deletion with Compacting)
要进一步提高性能,除了删除未引用的对象外,还可以压缩剩余的引用对象。
通过将引用的对象移动到一起,这使得新的内存分配更加容易和快速。
二、全自动回收管理
当正在进行垃圾收集时,如果你的应用程序在该时间段内没有响应时,其实我们的期望是,GC 应该花费最少的时间来回收它; 当然, 如果花费很多时间,则证明你的应用 GC 设置是有问题滴。
我们来看看下面的 JVM 内存模型,它分为不同的部分。JVM 堆内存在物理上分为两部分 - Young Generation(新生代)和 Old Generation(老年代)。
1.首先,将所有新的对象都分配给伊 Eden space(伊甸园)。两个 Survivor Space(幸存者区)都是空的。
2.当 Eden space(伊甸园)填满时,会触发一个小的垃圾收集。
3.引用的对象被移动到第一个幸存者空间。清除 Eden space(伊甸园)时,将删除未引用的对象。
4.下次要 GC 回收时,Eden space(伊甸园)空间也会发生同样的事情。删除未引用的对象,并将引用的对象移动到幸存者空间。但是,在这种情况下,它们被移动到第二个幸存者空间(S1)。
5.在较小的 GC 之后,当老化的对象达到一定的年龄阈值(在该示例中为 8)时,它们从新生代晋升到老年代。
最终,将对老一代进行主要的 GC 回收,清理和压缩该空间。
三、如何在 Java 中调整垃圾收集的优化参数呢?
垃圾收集是指当 JVM 不再需要对象时,需要将它回收,释放内存。它包括查找不再使用的对象,释放与这些对象关联的内存,并偶尔压缩堆以防止内存碎片。
垃圾收集器使用一个或多个线程来执行回收工作。一般来说,为了完成跟踪对象引用及在内存中移动对象的工作,它需要确保应用程序线程当前没有使用这些对象,如果应用程序线程正在使用对象,GC 回收时会导致对象的内存位置发生变化,可能发生不可预测的事情。这就是垃圾收集器在执行某些任务时必须暂停所有应用程序线程的原因。这些暂停有时被称为 Stop-The-World 暂停(吊炸天,全世界都被停止,哈哈)。
3.1 调整堆大小
垃圾收集调优的第一步是**调整堆的大小。**这是因为如果堆太小,则会发生太多的 GC 回收回收内存次数,这会降低整体应用程序吞吐量。如果堆太大,那么 GC 回收次数会更少,但 GC 需要很长的时间,那么你的系统响应时间指标会受到影响。并行收集器特别容易受到堆大小的影响,因此如果你需要大的堆并且暂停时间较短,那么你应该尝试使用 G1GC 收集器。
**备注:**自从 Java 9 和 Shenandoah 垃圾收集器被视为还处于“实验性”阶段,不推荐使用并发标记扫描(CMS)收集器。但如果你正在运行在线交互式应用程序,那么系统会默认选择 G1GC 收集器,如果你正在运行脱机批处理应用程序,那么并行收集器应该是你的首选,这是我给大家的建议。
**堆的大小由两个值控制:**使用 ms 标志指定的初始值和使用 mx 标志指定的最大值。
-Xms1g -Xmx8g
堆的初始大小和最大大小,可以由 JVM 根据工作负载自动调整堆大小。如果 JVM 遇到内存压力并且观察到 GC 执行次数过多,它会不断增加堆,直到内存压力消失为止,或直到堆达到其最大值为止。如果内存压力很低,JVM 还可以通过缩小堆大小来决定减少暂停时间。这个过程称为自适应大小调整**,**它不仅可以调整堆的整体大小,还可以调整年轻代和老代的大小和比例。
当然,如果你想调整 GC 行为和大小,**我建议你可以选择关闭自适应大小调整。**这可以节省 JVM,这是计算堆大小所需的一小段时间。你可以通过将标志设置 UseAdaptiveSizePolicy 为 false 来执行此
操作。
-XX:-UseAdaptiveSizePolicy
此外,将初始堆大小设置为与最大堆大小相同的值,或将初始新生代大小设置为与最大新生代大小相同的值,这样操作可以有效地关闭自适应大小调整。
一般来说堆大小的最大设置准则就是**最大堆大小不应超过计算机上的物理内存量。**如果你运行多个 JVM,则最大堆大小的总和不应超过计算机的物理内存。
3.2 调整 GC 性能
在 G1GC 中,调整参数 MaxGCPauseMillis 执行以下所有优化,以尝试实现指定的暂停时间目标:
调整堆的大小
更快开始后台处理
调整要提升为旧一代的对象的期限阈值
调整混合 GC 循环期间处理的旧区域数
3.3 修复并发模式失败
**G1GC 是一个并发收集器。**这意味着当应用程序线程仍在运行时,垃圾收集进程的某些阶段可以并发运行。并且由于正在运行的应用程序可以继续产生垃圾,我们可能会遇到应用程序耗尽旧代内存而垃圾收集器仍在垃圾收集过程中的情况。也就是说,正在运行的应用程序生成的垃圾比它清理的速度快。**这种情况称为并发模式故障,**具体取决于故障发生的时间。如果您在 GC 日志中看到很多这些错误; 解决方案是增加堆的大小,更早地启动 G1 后台处理,或者通过使用更多后台线程来加速 GC 处理。
要更频繁地执行 G1 后台活动,您可以降低触发 G1 循环的阈值。这是通过减少 InitiatingHeapOccupancyPercent 标志的值来实现的。
-XX:InitiatingHeapOccupancyPercent=45
默认情况下,此标志设置为 45。这意味着**当堆填充 45%时会触发 GC 循环。**减少此值意味着 GC 会更早且更频繁地触发。但应注意的是,该值不会设置为太低而导致 GC 过于频繁发生的数字。
要增加后台线程数,请使用该 ConcGCThreads 标志。
-XX:ConcGCThreads=4
此标志的默认值设置为 ParallelGCThreads 加 2 的值除以 4.只要计算机上有足够的 CPU 可用,就可以增加此值而不会导致任何性能损失。
评论