我们在JBoss上部署了一个大型JDK7应用程序,使用Hibernate,Spring等多个库。服务器初次启动后,应用程序按预期运行,但在正常运行一段时间后,它变得非常慢。JDK7应用程序正常运行一段时间后速度变慢
使用探查器,我们已经看到每次外部应用程序的某些方面正在放慢速度,但并不总是相同的方面。虽然在一次运行中可能是hibernate flush变慢,但在另一次运行中它可能是来自Spring的一些DI代码。
这是怎么回事?
我们在JBoss上部署了一个大型JDK7应用程序,使用Hibernate,Spring等多个库。服务器初次启动后,应用程序按预期运行,但在正常运行一段时间后,它变得非常慢。JDK7应用程序正常运行一段时间后速度变慢
使用探查器,我们已经看到每次外部应用程序的某些方面正在放慢速度,但并不总是相同的方面。虽然在一次运行中可能是hibernate flush变慢,但在另一次运行中它可能是来自Spring的一些DI代码。
这是怎么回事?
JDK7中存在一个CodeCache内存区域的问题,这个问题非常非常困难。
说明
基本上Java的启动和即时编译(JIT)使用在运行时只编译字节码所需的零件。这使JVM能够在执行期间解除和重新编译某些代码片段。如果JVM确定的话,这个发生的事情是,某个代码片段的初始编译不是最理想的。 Oracle在JDK 7中引入了名为分层编译的功能,该功能允许VM执行此操作。
JVM中的编译代码存储在CodeCache
存储区中。一直到JDK6默认情况下,这个区域将被填满,一旦达到100%,JIT将停止编译,并且会向控制台输出错误,但是应用程序会像以前一样运行:已编译的所有内容都将保持编译状态,所有尚未编译的内容都将在解释模式下执行(大约慢100倍)
此选项名为CodeCacheFlushing
,它自JDK7u4起默认启用。这个想法是,一旦CodeCache
已满,已编译代码的最少使用部分将从内存中刷新,为其他代码片段腾出空间。这将使JDK6默认行为(停止编译)完全废弃。它还允许一个更小的CodeCache区域(在JDK7 CodeCache中默认为48M,如果启用分层编译,则为96M)。
这是错误。在JDK7 CodeCache变满后,JIT停止。接下来是CodeCache区域的刷新。而已。冲洗完成后应重新启用JIT,但不会发生。此外,控制台上不会显示任何警告。更糟糕的是:在禁用JIT之前,大约有一半的已编译代码被抛出。
与JDK6相比,JDK6中所有速度都很快并且只能解释新代码,而在JDK7中,实际上已经丢失了已编译和优化的代码!所有表现良好的应用程序的突然部分将停止执行。应用程序的哪些部分放慢了速度,这使得通过Profiler跟踪该bug的几率几乎是不可能的:有时候,用于刷新的休眠代码在其他时间会减慢,在其他情况下,其代码为春季DI代码或您自己的应用代码。
受影响吗?
您可以使用Profiler(JProfiler/YourKit)或JConsole(JVisualVM不会)来监视CodeCache内存区域的内存消耗。通常,CodeCache金额committed
将保持非常接近used
的金额(例如,committed
是23mb,使用的是22mb)。在您的应用程序运行时,committed
和used
直到committed
达到max
。此时used
将急剧下降至max
的1/2 - 2/3。之后,used
不再增长。这就是错误会袭击你的地方。在JConsole中,它看起来就像这样:
为什么是我,而不是所有的人?
很可能你正在使用JBoss。甲骨文很快就发现,有些事情不像他们应该做的那样,默认情况下禁用了tiered compilation
- 然而红帽以其无限的智慧来决定,它知道更好,并且重新启用它。基本上,我们的Web应用程序在Weblogic上运行良好,只有JBoss受到影响,因为没有分层编译(weblogic中未启用),CodeCache的增长非常小,即使经过数周的运行,我们也从未达到过48mb的阈值。
我该怎么办?
首先,决定这个bug是否打到你。其次,让bug更难以伤害你。如果您禁用CodeCacheFlushing
至少击中错误不会让事情变得比以前更糟。停止tiered compilation
将使错误发生的可能性降低,与增加可用的CodeCache-Memory量相同。
您可以随时尝试切换到JDK8,这似乎不受影响,并且您也可以在软件中实施监视以警告您,如果CodeCache运行已满。
TL; DR
PRESERVE_JAVA_OPTS=true
-XX:-UseCodeCacheFlushing
)-XX:ReservedCodeCacheSize=xxM
)中。
链接到JDK问题:http://bugs.java.com/bugdatabase/view_bug.do?bug_id=8012547 –