【问题标题】:How to trigger collection of Old Generation in G1GC如何在 G1GC 中触发老年代的收集
【发布时间】:2019-04-18 18:33:23
【问题描述】:

最近,我们的一些服务器由于段错误而崩溃。虽然我没有一个已证实的根本原因,但我确实有一种预感,它与我们的应用程序的垃圾收集方式、我们所做的 GC 调整以及内存配置文件有关。

调查这些崩溃的多次发生,我从 JVM 的角度确定了一种模式:

  • 在崩溃之前,线程数增加到高于正常水平
  • 在崩溃之前,总体堆使用的一般正常锯齿模式消失了,堆大小没有减少地增长
  • 在崩溃之前,堆的年轻代一直很低,并且似乎没有调整大小或使用量增长
  • 在崩溃之前,老年代增长到比过去任何老年代都大的大小,并且似乎没有被清理或收集
  • 段错误总是与活动的 GC 线程有关,特别是 copy_to_survivor_space

虽然我没有看到内存不足发生的确凿证据,但我认为我们确实耗尽了应用程序的堆空间。如果 G1GC 无法在疏散或提升之前将年轻对象复制到幸存者空间,那么从逻辑上讲,它似乎没有足够的空间来这样做。分析 GC 日志,我看不出与 Humongous 对象有什么关系,因为我认为它们不会占用堆中的大量空间。

查看内存配置文件,我的直觉是我应该将InitiatingHeapOccupancyPercent 减小到接近默认值 45 的值,以便更早地触发收集周期。在我看来,尤其是考虑到老一代不断增长的规模,混合/完整 GC 需要更频繁地或至少更早地触发。 如何启动完整/混合收集?

根据所提供的信息,对于如何更快地触发收集还有其他想法或意见吗?我是否误解了段错误消息并走错了路?我还能做些什么来收集可能使我能够解决崩溃根本原因的信息?


Detail
# A fatal error has been detected by the Java Runtime Environment:
#
#  SIGSEGV (0xb) at pc=0x00007f38aa2655f5, pid=6293, tid=0x00007f3894efe700
#
# JRE version: Java(TM) SE Runtime Environment (8.0_162-b12) (build 1.8.0_162-b12)
# Java VM: Java HotSpot(TM) 64-Bit Server VM (25.162-b12 mixed mode linux-amd64 compressed oops)
# Problematic frame:
# V  [libjvm.so+0x5c85f5]  G1ParScanThreadState::copy_to_survivor_space(InCSetState, oopDesc*, markOopDesc*)+0x45
#

JVM 选项:

-XX:MaxHeapSize=30g
-XX:MetaspaceSize=256m
-XX:MaxMetaspaceSize=512m
-XX:+UseG1GC
-XX:MaxGCPauseMillis=200
-XX:InitiatingHeapOccupancyPercent=70
-XX:-OmitStackTraceInFastThrow
-XX:+AlwaysPreTouch
-XX:+UseStringDeduplication
-XX:+UseCompressedOops

-Xloggc:/usr/local/company/logs/gc.log
-XX:+UseGCLogFileRotation
-XX:NumberOfGCLogFiles=10
-XX:GCLogFileSize=100M
-XX:+PrintAdaptiveSizePolicy
-XX:+PrintGCApplicationConcurrentTime
-XX:+PrintGCApplicationStoppedTime
-XX:+PrintGCCause
-XX:+PrintGCDateStamps
-XX:+PrintGCDetails
-XX:+PrintGCTimeStamps
-XX:+PrintHeapAtGC
-XX:+PrintReferenceGC
-XX:+PrintTenuringDistribution
-XX:+HeapDumpOnOutOfMemoryError
-XX:HeapDumpPath=/usr/local/company/logs/heapdump_126960.hprof

【问题讨论】:

    标签: java garbage-collection g1gc


    【解决方案1】:

    我是否误解了段错误消息并走错了路?

    是的,堆 OOM 永远不会导致段错误,而应该只通过异常/可抛出机制触发 out of memory errors。崩溃签名指向由外部因素(加载到 JVM 进程中的本机库、内存损坏、Unsafe 的错误使用)导致的 JVM 错误或堆损坏。

    尝试升级您的 JVM 并查看原因是否已在较新版本中得到修复。如果这样做没有帮助,请尝试删除您的应用程序、依赖项、Java 代理等的部分内容或在不同的硬件上运行。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-06-24
      • 1970-01-01
      • 2016-07-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-04-18
      • 1970-01-01
      相关资源
      最近更新 更多