长话短说,我做了很多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上的开发人员可能对此问题有更多了解。
我的服务器配置:
Windows Server 2008 R2企业Service Pack 1(64位)
48 RAM
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
JDK7 Update 75 64位(路径为C:\ Program Files \ Java \ jdk1.7.0_75 \ jre \ bin \ server \ jvm.dll)
运行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