4

我有一个在独立 JVM 中运行的 Java 应用程序。该应用程序在一个或多个套接字上侦听数据,对数据进行排队,并安排线程将数据从队列中拉出并持久化。数据很宽,每条记录有超过 700 个数据元素,尽管所有数据元素都是小字符串、整数或长整数。

该应用程序可以平稳运行一段时间,有时是 30 分钟到一个小时,但随后我们会遇到一个或多个长时间的垃圾收集暂停。大部分暂停时间都花在对象复制时间上。相对于其他集合,系统时间也很高。

这是JVM详细信息:

java version "1.7.0_03" 
Java(TM) SE Runtime Environment (build 1.7.0_03-b04) 
Java HotSpot(TM) 64-Bit Server VM (build 22.1-b02, mixed mode)

以下是 JVM 选项:

-XX:MaxPermSize=256m -XX:PermSize=256m -Xms3G -Xmx3G -XX:+UseG1GC -XX:-UseGCOverheadLimit 

该过程是 4 个核心的任务集(全部在同一个插槽上),但几乎不使用其中的 2 个。这个盒子上的所有进程都固定在它们自己的核心上(0 和 1 未使用)。机器有大量可用内存(20+G),上图显示使用2.5G RES内存的进程。

这是一些 gc 日志输出...

[Object Copy (ms): 2090.4 2224.0 2484.0 2160.1 1603.9 2071.2 887.8 1608.1 1992.0 2030.5 1692.5 1583.9 2140.3 1703.0 2174.0 1949.5 1941.1 2190.1 2153.3 1604.1 1930.8 1892.6 1651.9

[Eden: 1017M(1017M)->0B(1016M) Survivors: 7168K->8192K Heap: 1062M(3072M)->47M(3072M)] 

[Times: user=2.24 sys=7.22, real=2.49 secs]

关于为什么对象复制时间和系统时间如此之高以及如何纠正它的任何想法?日志中有许多垃圾收集,它们的 Eden/Survivors/Heap 大小几乎相同,只需要 10 或 20 毫秒。

4

2 回答 2

1

3gb 不是一个大堆,幸存者大小也很小。在这些内核上运行的还有其他东西吗?你产生了多少垃圾,它收集的频率是多少?您可能也想在没有 G1GC 的情况下尝试它。

于 2013-12-13T20:48:29.047 回答
0

需要3 GB 的堆吗?随着堆变大,垃圾收集暂停会变长,因为(尽管频率较低)最终需要 GC 时还有更多工作要做。

看来您通过设置最小值将堆锁定在 3 gig。如果应用程序不需要 3 gig,无论如何这将迫使它使用那么多......当最终确实需要收集 3G 时,会导致巨大的停顿。

我花了很多时间调整 Eclipse IDE 的响应能力,并且很早就发现紧凑堆大小比大堆具有更好的“低暂停”特性。

除了 JVM 堆设置之外,您还可以确保您的代码“清空”数据元素和集合项,因为它们被丢弃。

这是java.utilCollections 包中的标准做法,但也许您的代码可以从中受益。700 条记录尤其适合这种做法,这有助于简化 GC 的工作,并能更好地清理“次要 GC”扫描。

于 2013-11-14T19:15:15.723 回答