为什么在Tomcat运行一周后,创建1到2项int数组突然成为缓慢的瓶颈?

时间:2016-05-23 10:10:59

标签: java performance tomcat groovy jvm

长话短说,我做了很多Thread Dumps得出结论,在我的Tomcat减速期间,创建带有1或2项的int数组成为我系统的许多代码的瓶颈。有关详细信息,请继续阅读。

这种情况已经发生了很多次,每次发生时,我都要重新启动Tomcat以恢复正常速度。

我的Tomcat服务器运行正常。但大约一周后(大多数时间从4天到10天不等),我的Tomcat在大多数操作中变得缓慢。为了检查原因,我创建了一些基准测试函数,运行它们,并采用许多线程转储。

我的基准功能之一如下:

while (System.currentTimeMillis() < someEndTime) {  // I run this loop for 5 seconds
    2.power(3)  // Note that this function is Groovy code
    loopCount++
}
// The higher the loopCount after the loop is passed, the faster it is

请注意,我将我的线程转储分为2个时段:&#34;慢时段&#34;还有正常时期&#34;。

在&#34;慢时段&#34;中,变量loopCount在&#34;正常时段&#34;期间大约是其值的十分之一,这意味着它慢了10倍。

在缓慢的时期,10个螺纹转储中,其中8个如下:

"http-nio-8443-exec-43" daemon prio=6 tid=0x000000004be6a000 nid=0x58f4 runnable [0x0000000067bcc000]
   java.lang.Thread.State: RUNNABLE
    at java.math.BigInteger.pow(BigInteger.java:1402)
    at org.codehaus.groovy.runtime.DefaultGroovyMethods.power(DefaultGroovyMethods.java:8984)
    at org.codehaus.groovy.runtime.dgm$473.invoke(Unknown Source)
    at org.codehaus.groovy.runtime.callsite.PojoMetaMethodSite$PojoMetaMethodSiteNoUnwrapNoCoerce.invoke(PojoMetaMethodSite.java:270)
    at org.codehaus.groovy.runtime.callsite.PojoMetaMethodSite.call(PojoMetaMethodSite.java:52)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:124)
    at com.mycompany.myproduct.TestController$_closure11.doCall(TestController.groovy:241)

我的Tomcat服务器的JDK是JDK7 Update 75,因此BigInteger.java:1402对应于:

int[] result = {1};

这是一个单项数组创建。

剩余的2个螺纹转储(10个中)如下:

"http-nio-8443-exec-38" daemon prio=6 tid=0x000000005e5f8000 nid=0x22e0 runnable [0x0000000063f9c000]
   java.lang.Thread.State: RUNNABLE
    at java.util.Arrays.copyOfRange(Arrays.java:2622)
    at java.math.BigInteger.trustedStripLeadingZeroInts(BigInteger.java:2826)
    at java.math.BigInteger.pow(BigInteger.java:1412)
    at org.codehaus.groovy.runtime.DefaultGroovyMethods.power(DefaultGroovyMethods.java:8984)
    at org.codehaus.groovy.runtime.dgm$473.invoke(Unknown Source)
    at org.codehaus.groovy.runtime.callsite.PojoMetaMethodSite$PojoMetaMethodSiteNoUnwrapNoCoerce.invoke(PojoMetaMethodSite.java:270)
    at org.codehaus.groovy.runtime.callsite.PojoMetaMethodSite.call(PojoMetaMethodSite.java:52)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:124)
    at com.mycompany.myproduct.TestController$_closure11.doCall(TestController.groovy:241)

在同一个JDK中,Arrays.java:2622对应于:

int[] copy = new int[newLength];

其中一个数组创建1或2个项目(对于2.power(3),newLength最多为2,如果复制相关的JDK源代码并进行测试)。

在&#34;慢周期&#34;中的10个线程转储中,所有堆栈跟踪都在创建具有1到2个项目的int数组。 这证明了&#34;缓慢时期的瓶颈&#34;正在创建包含1到2个项目的int数组。

此外,记忆力还没有填满。上周峰值堆使用量为7GB,而最大堆大小为24GB。此外,如果内存已满,将会有大量其他更大的对象(例如BigInteger本身)而不是2项数组成为内存分配瓶颈,以及&#34;缓慢时期的堆栈跟踪&#34 ;会有所不同。

当&#34;慢时期&#34;碰巧,我必须重新启动Tomcat才能使速度恢复正常。

在&#34;正常时期&#34;当我的Tomcat通常快几倍时,我也会采用相同基准测试功能的几个Thread Dump。 我没有看到数组创建是瓶颈。 Belows就是例子:

"http-nio-8443-exec-4" daemon prio=6 tid=0x000000004d22b000 nid=0x163c runnable [0x000000005820a000]
   java.lang.Thread.State: RUNNABLE
    at org.codehaus.groovy.runtime.typehandling.LongMath.compareToImpl(LongMath.java:50)
    at org.codehaus.groovy.runtime.typehandling.NumberMath.compareTo(NumberMath.java:69)
    at org.codehaus.groovy.runtime.DefaultGroovyMethods.compareTo(DefaultGroovyMethods.java:8791)
    at org.codehaus.groovy.runtime.typehandling.DefaultTypeTransformation.compareToWithEqualityCheck(DefaultTypeTransformation.java:540)
    at org.codehaus.groovy.runtime.typehandling.DefaultTypeTransformation.compareTo(DefaultTypeTransformation.java:521)
    at org.codehaus.groovy.runtime.ScriptBytecodeAdapter.compareTo(ScriptBytecodeAdapter.java:692)
    at org.codehaus.groovy.runtime.ScriptBytecodeAdapter.compareLessThan(ScriptBytecodeAdapter.java:701)
    at com.mycompany.myproduct.TestController$_closure11.doCall(TestController.groovy:240)

"http-nio-8443-exec-22" daemon prio=6 tid=0x000000004d248000 nid=0x1988 runnable [0x0000000059b6c000]
   java.lang.Thread.State: RUNNABLE
    at java.math.BigInteger.pow(BigInteger.java:1406)
    at org.codehaus.groovy.runtime.DefaultGroovyMethods.power(DefaultGroovyMethods.java:8984)
    at org.codehaus.groovy.runtime.dgm$473.invoke(Unknown Source)
    at org.codehaus.groovy.runtime.callsite.PojoMetaMethodSite$PojoMetaMethodSiteNoUnwrapNoCoerce.invoke(PojoMetaMethodSite.java:270)
    at org.codehaus.groovy.runtime.callsite.PojoMetaMethodSite.call(PojoMetaMethodSite.java:52)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:124)
    at com.mycompany.myproduct.TestController$_closure11.doCall(TestController.groovy:241)

"http-nio-8443-exec-14" daemon prio=6 tid=0x000000004d242000 nid=0x7790 runnable [0x000000005910c000]
   java.lang.Thread.State: RUNNABLE
    at org.codehaus.groovy.runtime.DefaultGroovyMethods.power(DefaultGroovyMethods.java:8984)
    at org.codehaus.groovy.runtime.dgm$473.invoke(Unknown Source)
    at org.codehaus.groovy.runtime.callsite.PojoMetaMethodSite$PojoMetaMethodSiteNoUnwrapNoCoerce.invoke(PojoMetaMethodSite.java:270)
    at org.codehaus.groovy.runtime.callsite.PojoMetaMethodSite.call(PojoMetaMethodSite.java:52)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:124)
    at com.mycompany.myproduct.TestController$_closure11.doCall(TestController.groovy:241)

DefaultGroovyMethods是Groovy发行版(1.7.5版)的一部分。

总结一下,我的问题是: 为什么创建具有1到2个项目的int数组突然变得缓慢并成为&#34;慢速期间的瓶颈&#34;从4天到10天跑完Tomcat之后?为什么创建这样的数组比代码的其他部分慢?

它似乎与JVM本身有关,因此JDK上的开发人员可能对此问题有更多了解。

我的服务器配置:

  1. Windows Server 2008 R2企业Service Pack 1(64位)

  2. 48 RAM

  3. Tomcat Java选项:

    -Xms256m
    -Xmx24576m
    -XX:NewSize=64m
    -XX:PermSize=64m
    -XX:MaxNewSize=1024m
    -XX:MaxPermSize=1536m
    -Dcatalina.home=C:\mycompany\Tomcat7 OF MYPRODUCT
    -Dcatalina.base=C:\mycompany\Tomcat7 OF MYPRODUCT
    -Djava.endorsed.dirs=C:\mycompany\Tomcat7 OF MYPRODUCT\endorsed
    -Djava.io.tmpdir=C:\mycompany\Tomcat7 OF MYPRODUCT\temp
    -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager
    -Djava.util.logging.config.file=C:\mycompany\Tomcat7 OF MYPRODUCT\conf\logging.properties
    -Dstringchararrayaccessor.disabled=true
    
  4. JDK7 Update 75 64位(路径为C:\ Program Files \ Java \ jdk1.7.0_75 \ jre \ bin \ server \ jvm.dll)

  5. Groovy 1.7.5
  6. Grails 1.3.5
  7. 运行version.bat:

    的输出
    Server version: Apache Tomcat/7.0.59
    Server built:   Jan 28 2015 15:51:10 UTC
    Server number:  7.0.59.0
    OS Name:        Windows Server 2008 R2
    OS Version:     6.1
    Architecture:   amd64
    JVM Version:    1.7.0_75-b13
    JVM Vendor:     Oracle Corporation
    

1 个答案:

答案 0 :(得分:1)

这个答案解决了我的问题。

https://stackoverflow.com/a/25941663/857194

关于增加代码缓存的最大大小