10

经过4 到 24 小时4 到 8 天的压力测试(30 个线程在600 万页浏览量/天)。这是在 RHEL 5.2 (Tikanga) 上。

崩溃报告位于http://pastebin.com/f639a6cf1,崩溃的一致部分是:

  • 一个 SIGSEGV 被抛出
  • 在 libjvm.so 上
  • 伊甸园空间总是满的 (100%)

JVM 使用以下选项运行:

CATALINA_OPTS="-server -Xms512m -Xmx1024m -Djava.awt.headless=true"

我还使用http://memtest.org/测试了内存的硬件问题48 小时(整个内存的 14 次通过),没有任何错误。

我已经启用-verbose:gc -XX:+PrintGCDetails -XX:+PrintGCTimeStamps了检查任何 GC 趋势或空间耗尽但那里没有任何可疑之处。GC 和完全 GC 以可预测的时间间隔发生,几乎总是释放相同数量的内存容量。

我的应用程序不直接使用任何本机代码。

关于我接下来应该看哪里的任何想法?

编辑 - 更多信息

1)这个JDK中没有客户端vm:

[foo@localhost ~]$ java -version -server
java version "1.6.0_18"
Java(TM) SE Runtime Environment (build 1.6.0_18-b07)
Java HotSpot(TM) 64-Bit Server VM (build 16.0-b13, mixed mode)

[foo@localhost ~]$ java -version -client
java version "1.6.0_18"
Java(TM) SE Runtime Environment (build 1.6.0_18-b07)
Java HotSpot(TM) 64-Bit Server VM (build 16.0-b13, mixed mode)

2) 无法更改操作系统。

3) 我不想更改 JMeter 压力测试变量,因为这可能会隐藏问题。由于我有一个使 JVM 崩溃的用例(当前的压力测试场景),我想修复崩溃而不更改测试。

4)我已经对我的应用程序进行了静态分析,但没有出现任何严重问题。

5)内存不会随时间增长。内存使用量以非常稳定的趋势非常迅速地平衡(启动后),这似乎并不可疑。

6) /var/log/messages 在崩溃之前或期间不包含任何有用的信息

更多信息:忘了提到有一个使用 mod_jk 1.2.28 的 apache (2.2.14) 前端 tomcat。现在我在没有 apache 的情况下运行测试,以防 JVM 崩溃与连接到 JVM(tomcat 连接器)的 mod_jk 本机代码有关。

之后(如果 JVM 再次崩溃)我将尝试从我的应用程序中删除一些组件(缓存、lucene、quartz),稍后将尝试使用码头。由于崩溃目前在 4 小时到 8 天之间的任何时间发生,因此可能需要很长时间才能查明发生了什么。

4

7 回答 7

4

你有编译器输出吗?即PrintCompilation(如果你觉得特别勇敢,LogCompilation)。

我通过观察编译器正在做什么来调试这样的案例,最终(这花了很长时间直到灯泡时刻),意识到我的崩溃是由在 oracle jdbc 驱动程序中编译特定方法引起的.

基本上我要做的是;

  • 打开打印编译
  • 因为这没有给出时间戳,所以编写一个脚本来监视该日志文件(例如每秒睡眠并打印新行)并报告方法何时编译(或不编译)
  • 重复测试
  • 检查编译器输出以查看崩溃是否与某些方法的编译相对应
  • 多重复几次,看看有没有规律

如果存在可辨别的模式,则使用 .hotspot_compiler(或 .hotspotrc)使其停止编译有问题的方法,重复测试并查看它是否不会崩溃。显然,在你的情况下,这个过程理论上可能需要几个月的时间。

一些参考资料

我要做的另一件事是系统地更改您正在使用的 gc 算法根据 gc 活动检查崩溃时间(例如,它是否与年轻或老 gc 相关,TLAB 呢?)。您的转储表明您正在使用并行清除,因此请尝试

  • 串行(年轻)收集器(IIRC,它可以与并行旧)
  • ParNew + CMS
  • G1

如果它没有在不同的 GC 算法中再次出现,那么您就知道是这样(并且您没有解决办法,只能更改 GC 算法和/或返回旧的 JVM,直到您找到该算法的一个不会崩溃的版本)。

于 2010-02-28T21:01:45.020 回答
3

一些想法:

  • 使用不同的 JDK、Tomcat 和/或操作系统版本
  • 稍微修改测试参数,例如 25 个线程,每天 720 万次浏览量
  • 监控或分析内存使用情况
  • 调试或调整垃圾收集器
  • 运行静态和动态分析
于 2010-02-24T03:19:32.703 回答
2

你试过不同的硬件吗?看起来您使用的是 64 位架构。根据我自己的经验,32 位更快、更稳定。也许某处也存在硬件问题。“4-24 小时之间”的时间很分散,只是一个软件问题。尽管您确实说系统日志没有错误,但我可能会走远。还是觉得值得一试。

于 2010-02-24T22:50:41.027 回答
1

你的记忆会随着时间的推移而增长吗?如果是这样,我建议将内存限制更改得更低,以查看内存耗尽时系统是否更频繁地发生故障。

如果出现以下情况,您能否更快地重现问题:

  • 您减少了 JVM 可用的内存?
  • 您减少了可用的系统资源(即耗尽系统内存,因此 JVM 没有足够的资源)
  • 您将用例更改为更简单的模型?

我使用的主要策略之一是确定导致问题的用例。这可能是一个通用问题,也可能是特定于用例的问题。尝试记录用例的开始和停止,看看您是否可以确定哪些用例更有可能导致问题。如果您将用例分成两半,请查看哪一半失败最快。这可能是导致失败的更常见原因。自然地,对每种配置进行几次试验会提高测量的准确性。

我也知道要么改变服务器做很少的工作,要么循环服务器正在做的工作。一个使您的应用程序代码更难工作,另一个使 Web 服务器和应用程序服务器更难工作。

祝你好运,雅各布

于 2010-02-24T03:26:47.247 回答
1

尝试将您的 servlet 容器从 Tomcat 切换到 Jetty http://jetty.codehaus.org/jetty/

于 2010-02-24T21:01:57.263 回答
1

如果我是你,我会做以下事情:

  • 尝试稍旧的 Tomcat/JVM 版本。你似乎正在运行最新和最伟大的。我会下降两个版本左右,可能会尝试 JRockit JVM。
  • 在应用程序运行时执行线程转储(kill -3 java_pid)以查看完整堆栈。您当前的转储显示许多线程被阻塞 - 但不清楚它们在哪里阻塞(I/O?一些内部锁饥饿?还有什么?)。我什至可能会安排kill -3每分钟运行一次,以将任何随机线程转储与崩溃前的线程转储进行比较。
  • 我见过 Linux JDK 死机而 Windows JDK 能够优雅地捕获异常(当时是 StackOverflowException)的情况,因此如果您可以修改代码,请在顶级类的某处添加“catch Throwable”。以防万一。
  • 使用 GC 调整选项。开启/关闭并发 GC,调整 NewSize/MaxNewSize。是的,这不是科学的——而是迫切需要有效的解决方案。更多细节在这里:http: //java.sun.com/javase/technologies/hotspot/gc/gc_tuning_6.html

让我们知道这是如何解决的!

于 2010-02-24T22:43:24.343 回答
1

是否可以改为使用 32 位 JVM?我相信这是 Sun 提供的最成熟的产品。

于 2010-02-27T09:10:21.820 回答