Som背景信息;

服务器;

新的具有130 GB Ram的SLES 12服务器旨在为大型数据库(150G +数据)运行MySQL。

该服务器还将托管一些Java应用程序。

Java版本(Oracle的默认版本)-Java(TM)SE运行时环境(内部版本1.7.0-b147)-Java HotSpot(TM)64位服务器VM(内部版本21.0-b17,混合模式)

我们偶然发现了以下问题;

运行某些特殊的Java应用程序会使kerne/system cpu峰值在一段时间内减慢/暂停应用程序。我通过制作一个Java应用程序来重现它,该Java应用程序会随着时间的流逝而消耗内存并使用一些cpu。

调查显示,减速期间的内部事件数量很高(10000-25000)。

每次减速后,Java需要更多的内存。将Java设置为从固定内存开始似乎也可以减少问题(将-Xmx和-Xms设置为相同的值)。详细说明垃圾回收还表明GC正在启动,并且可能是触发器。

由于某种原因,GC和内存分配非常昂贵,我们不确定从哪里可以看到。来自GC的详细信息:

[GC^C 1024064K->259230K(3925376K), 87,3591890 secs]

在低端linux服务器上,同一程序运行GC(运行SUN的SLES,Java 1.6.0_11);
[GC 1092288K->253266K(3959488K), 3.0125460 secs]

减速期间的TOP:
top - 11:23:33 up 87 days, 19:55,  5 users,  load average: 14.27, 4.50, 10.17
Tasks: 250 total,  39 running, 211 sleeping,   0 stopped,   0 zombie
Cpu(s):  0.0%us, 71.8%sy,  0.0%ni, 28.2%id,  0.0%wa,  0.0%hi,  0.0%si,  0.0%st
Mem:    129033M total,   128576M used,      457M free,     1388M buffers
Swap:    32765M total,       13M used,    32752M free,   113732M cached

减速期间 vmstat(从第3行开始);
procs -----------memory---------- ---swap-- -----io---- -system-- -----cpu------
 r  b   swpd   free   buff  cache   si   so    bi    bo   in   cs us sy id wa st
 0  0  13552 1714328 1422268 116462260    0    0    10     9    0    0  0  0 100  0  0
 1  0  13552 1241780 1422268 116462292    0    0     0     0  240  353  1  0 99  0  0
 1  0  13552 695616 1422268 116462292    0    0     0    17  419  431  3  0 97  0  0
55  0  13552 486384 1422268 116462292    0    0     0     2 20228  458  1 57 43  0  0
75  0  13552 476172 1422268 116462300    0    0     0     8 12782  684  0 70 30  0  0
65  0  13552 470304 1422268 116462304    0    0     0     0 13108  792  0 72 28  0  0

为什么GC在高端服务器与低端服务器上如此昂贵?有什么想法可以找到线索吗?

更新-调用参数2012-11-26
调用参数;
java -Xmx4g -Xms4g -verbose:gc -server -cp "./dest/" UseMemoryMain

给予
[GC^C 1024064K->259230K(3925376K), 87,3591890 secs]

变成;
java -Xmx4g -Xms4g -XX:+UseParallelGC -verbose:gc -cp "./dest/" UseMemoryMain

给予
[GC 1048640K->265430K(4019584K), 0,0902660 secs]

变成;
java -Xmx4g -Xms4g -XX:+UseConcMarkSweepGC -verbose:gc -cp "./dest/" UseMemoryMain

给予
[GC 1092288K->272230K(3959488K), 0,1791320 secs]

真正有趣的是,今天重新运行 ,而没有告知要使​​用哪种GC方法;
java -Xmx4g -Xms4g -verbose:gc -server -cp "./dest/" UseMemoryMain

给予
[GC 1024064K->259238K(3925376K), 0,0839190 secs]

Java已更改以某种方式默认使用GC的策略...

最佳答案

垃圾回收确实是一个棘手的话题。
为了提供最佳答案,您应该发布用于调用Java的完整命令行。

就像您说的那样,使用GC开关可以帮助您。原因是不幸的是,默认设置对于最近使用的许多应用程序不是最佳的。对于许多需要快速响应的应用程序(因为它们是交互式的),参数

-XX:+ UseConcMarkSweepGC

将会有很大的不同。

值得注意的是,使用您提到的JVM,使用更大的堆(比如说更大的10GB)将始终需要进行一些调整。拿走您拥有的GC日志,观察使用GC选项时行为如何变化。我建议您尝试使用不同的收集器策略(例如CMS或G1),并尝试使用Eden Space的配置(例如Xmn)。

最后但并非最不重要的一点是,您可以使用探查器调查应用程序对内存的处理方式。也许可以改进代码,从而可以避免很多GC。

10-07 19:34
查看更多