java - 如何诊断无休止的 JVM GC 运行?

标签 java garbage-collection jvm jvm-hotspot

我们的生产服务器上有一个堆大小为几千兆字节的 Java EE 应用程序。每隔一段时间,我们的任何一台服务器都不再响应任何请求。

  • 当问题发生时,GC 日志表明服务器正在花费大量/大部分时间运行 GC,这需要 8 到 10 秒(通常少于 1 秒)。
  • 我们永远不会遇到任何 OutOfMemoryErrors。
  • 问题不会在堆达到特定堆大小时出现 - 事实上,它会出现在不同的堆大小上,甚至没有一个接近配置的最大值。
  • 问题不会在特定时间间隔、特定时间、用户负载或特定服务器节点上发生。这似乎完全是随机的。
  • 堆转储,即使是在出现问题时从服务器获取的堆转储,也没有显示任何明显错误的内容。
  • 每天重新启动生产服务器似乎可以降低问题发生的可能性,但并不能解决问题。
  • 如果我们不每天重新启动我们的服务器,那么问题很可能会在一到三天内出现在我们的 8 台生产服务器中的一台上。

您将如何开始对此进行诊断?

配置

我们的 JAVA_OPTS 如下: -Xms8096m -Xmx8096m -XX:MaxPermSize=512M -Dsun.rmi.dgc.client.gcInterval=1800000 -Dsun.rmi.dgc.server.gcInterval=1800000 -XX:NewSize=150M -XX:+UseParNewGC -XX :+PrintGCDetails -XX:+PrintGCTimeStamps -Xloggc:/path/to/gc.log

$ java -version
java version "1.6.0_12"
Java(TM) SE Runtime Environment (build 1.6.0_12-b04)
Java HotSpot(TM) 64-Bit Server VM (build 11.2-b01, mixed mode)

$ uname -a
Linux myhostname 2.6.18-274.3.1.el5 #1 SMP Tue Sep 6 20:13:52 EDT 2011 x86_64 x86_64 x86_64 GNU/Linux

$ cat /proc/version
Linux version 2.6.18-274.3.1.el5 (mockbuild@builder10.centos.org) (gcc version 4.1.2 20080704 (Red Hat 4.1.2-51)) #1 SMP Tue Sep 6 20:13:52 EDT 2011

$ cat /etc/issue
CentOS release 5.7 (Final)
Kernel \r on an \m

$ cat /proc/meminfo|grep "MemTotal"
MemTotal:     16279356 kB

GC日志

这是发生问题时的示例 GC 日志片段:

111036.554: [GC 111036.555: [ParNew: 2210816K->2210816K(2487104K), 0.0000090 secs]111036.555: [Tenured: 3629252K->3647971K(5526912K), 8.7565190 secs] 5840068K->3647971K(8014016K), 8.7567840 secs]
111055.691: [GC 111055.691: [ParNew: 2210816K->2210816K(2487104K), 0.0000090 secs]111055.691: [Tenured: 3647971K->3667529K(5526912K), 8.7876340 secs] 5858787K->3667529K(8014016K), 8.7878690 secs]
111071.037: [GC 111071.037: [ParNew: 2210816K->2210816K(2487104K), 0.0000090 secs]111071.037: [Tenured: 3667529K->3692057K(5526912K), 8.7581830 secs] 5878345K->3692057K(8014016K), 8.7584210 secs]
111088.407: [GC 111088.407: [ParNew: 2210816K->2210816K(2487104K), 0.0000090 secs]111088.407: [Tenured: 3692057K->3638194K(5526912K), 10.7072790 secs] 5902873K->3638194K(8014016K), 10.7074960 secs]
111110.238: [GC 111110.238: [ParNew: 2210816K->2210816K(2487104K), 0.0000090 secs]111110.238: [Tenured: 3638194K->3654614K(5526912K), 8.8021440 secs] 5849010K->3654614K(8014016K), 8.8023860 secs]
111128.115: [GC 111128.115: [ParNew: 2210816K->2210816K(2487104K), 0.0000090 secs]111128.115: [Tenured: 3654614K->3668670K(5526912K), 8.8451510 secs] 5865430K->3668670K(8014016K), 8.8453600 secs]
111161.684: [GC 111161.684: [ParNew: 2210816K->2210816K(2487104K), 0.0000090 secs]111161.684: [Tenured: 3668670K->3684080K(5526912K), 8.8156740 secs] 5879486K->3684080K(8014016K), 8.8159260 secs]
111186.669: [GC 111186.669: [ParNew: 2210816K->2210816K(2487104K), 0.0000090 secs]111186.669: [Tenured: 3684080K->3639333K(5526912K), 10.6025350 secs] 5894896K->3639333K(8014016K), 10.6030040 secs]
111208.692: [GC 111208.692: [ParNew: 2210816K->2210816K(2487104K), 0.0000090 secs]111208.692: [Tenured: 3639333K->3657993K(5526912K), 8.7967920 secs] 5850149K->3657993K(8014016K), 8.7970090 secs]
111235.486: [GC 111235.487: [ParNew: 2210816K->2210816K(2487104K), 0.0000090 secs]111235.487: [Tenured: 3657993K->3676521K(5526912K), 8.8212340 secs] 5868809K->3676521K(8014016K), 8.8214930 secs]

最佳答案

由于您使用的是非常旧的 Java 版本(将近四年)并且您似乎进入了错误状态,因此首先要尝试更新版本,例如 Java 6 update 35。我怀疑 update 12 不会'默认情况下启用 Compressed Oops,这是一个可以为您节省一些内存(从而节省开销)的选项

关于java - 如何诊断无休止的 JVM GC 运行?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13628484/

相关文章:

java - 在 Spring Batch 中配置多个数据源时出现无法解决的循环引用错误

java - 大型 Java 系统依赖管理

java - 对于从下拉框中选择的特定值,在下拉列表中显示其对应的值吗?

java - JVM Tenured/Old gen 达到限制和服务器挂起

java - .net 的 GC.KeepAlive 的 Java 等价物是什么?

garbage-collection - JVM 中的安全点

java - 如何从 Set/Map 中删除多个元素并知道哪些元素被删除了?

Android应用程序内存堆不断增长

java - Jave 如何防止并发类初始化发生?

java - 我在 Linux 上有一台 8 GB RAM 和 32 位 JVM 的机器,我想让 JVM 最大程度地使用 RAM