我们使用多个库(例如Hibernate,Spring等)在JBoss上部署了一个大型JDK7应用程序。最初启动服务器后,该应用程序将按预期运行,但是在正常运行时间后,它将变得非常缓慢。

使用探查器,我们已经看到,每次外发应用程序的某些方面变慢时,但并不总是相同的方面。在一次运行中,可能是休眠刷新速度变慢,而在另一次运行中,可能是Spring发出的一些DI代码。

那里发生了什么事?

最佳答案

JDK7中有一个关于CodeCache内存区域的错误,这非常非常严重地打击了我们。

说明

基本上,Java会启动,并使用即时编译(JIT)来在运行时仅编译字节码的必需部分。这使JVM可以在执行过程中反编译某些代码片段并重新编译它们。如果JVM确定,则会发生某个代码片段的初始编译不理想的情况。 Oracle在JDK 7中引入了一个名为“分层编译”的功能,该功能使VM可以做到这一点。

JVM中的已编译代码存储在CodeCache内存区域中。直到JDK6为止,默认设置是该区域将被填充,并且JIT一旦达到100%,JIT将停止编译并且将向控制台打印错误,但是该应用程序将与以前相同地运行:已编译的所有内容将保持编译状态,所有尚未编译的内容都将以解释模式执行(速度大约慢100倍)

此选项名为CodeCacheFlushing,自JDK7u4起默认启用。这样做的想法是,一旦CodeCache满了,就会从内存中清除最不常用的编译代码部分,以便为其他代码片段腾出空间。这将使JDK6-default-behaviour(停止所有编译)成为过时。它还允许使用更小的CodeCache区域(在JDK7中,默认情况下,CodeCache为48M,如果启用了分层编译,则为96M)。

错误来了。在JDK7中,一旦CodeCache满了,JIT就停止了。接下来是CodeCache区域的刷新。就是这样。刷新完成后应重新启用JIT,但这不会发生。另外,控制台上没有警告打印。更糟:在禁用JIT之前,大约一半的已编译代码被丢弃。

与JDK6相比,所有快速的东西都将保持快速状态,只有新代码将被解释,而在JDK7中,您实际上会丢失已经编译和优化的代码!应用程序中所有突然出现问题的部分都将停止运行。剩下的机会是,应用程序的哪些部分速度变慢,这使得通过探查器跟踪该错误几乎是不可能的:有时用于刷新的休眠代码会减慢其Spring DI代码或您自己的应用程序代码的速度。

您受到影响了吗?

您可以使用探查器(JProfiler/YourKit)或JConsole(不会使用JVisualVM)来监视CodeCache内存区域的内存消耗。通常,CodeCache量committed将保持非常接近used量(例如committed为23mb,已使用为22mb)。在您的应用程序运行时,committedused会上升,直到committed达到max为止。那时used将急剧下降至max的1/2-2/3。在那之后,used将不再增长。那就是错误会打击您的地方。在JConsole中,它将如下所示:

performance - 正常运行时间后,JDK7应用程序变慢-LMLPHP

为什么不是我而是所有其他人?

很有可能,您正在使用JBoss。 Oracle很快发现有些事情不应该发生,并且默认情况下禁用了tiered compilation-但是Red Hat以其无限的智慧决定了,它更好地了解并重新启用了它。基本上,我们的web应用程序可以在Weblogic上正常运行,并且只影响JBoss,因为没有分层编译(在weblogic中未启用),CodeCache的增长是如此之小,即使经过数周的运行,我们也从未真正达到48mb的阈值。

我该怎么办?

首先,请确定此bug是否击中了您。其次,使错误更难以损坏您。如果禁用CodeCacheFlushing,至少击中该bug不会使事情变得比以前更糟。停止tiered compilation可以减少您遇到该错误的可能性,就像增加可用的CodeCache-Memory数量一样。

您始终可以尝试切换到JDK8,这似乎不受影响,并且如果CodeCache运行满了,您还可以在软件中实现监视以警告您。

TL; DR

  • 在JDK 7中,永远不要启用分层编译(默认情况下已禁用,已在JBoss中启用)
  • JBoss 7中的
  • 总是在standalone.conf中设置PRESERVE_JAVA_OPTS=true
  • 总是禁用CodeCacheFlushing(-XX:-UseCodeCacheFlushing)
  • 总是将足够量的内存打包到CodeCache(-XX:ReservedCodeCacheSize=xxM)中。
  • 关于performance - 正常运行时间后,JDK7应用程序变慢,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/38393071/

    10-11 23:59