导致tomcat内存增长和下降的原因
答案 0 :(得分:5)
jconsole本身会导致锯齿形图案。
要查看jconsole
或jvisualvm
的效果,您可以只使用主循环编写一个简单的java程序。 E.g。
public static void main(String[] args) {
while (true) {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
}
}
}
只用一小堆java -Xmx20m ...
执行它。这将有助于您更好地查看堆利用率,因为我将使用的工具jstat
以百分比形式打印利用率。
现在打开命令行窗口并执行jstat
。您将需要java进程的PID,并可以使用jps -l
找到它。
jstat -gcutil <PID>
它会打印出类似这样的内容
S0 S1 E O M CCS YGC YGCT FGC FGCT GCT
0,00 0,00 69,34 0,00 14,48 17,19 0 0,000 0 0,000 0,000
关注伊甸园空间E
。该值是空间当前容量的百分比。有关详细信息,请查看jstat。
如果您反复执行该命令,您将看到伊甸园空间利用率不会增长。它保持在例如69,34
。我在Windows上使用类似linux的命令来以特定间隔重新运行命令。见watch.bat
现在打开jconsole
jconsole <PID>
并一次又一次地执行jstat
命令。您将看到伊甸园空间不断增长,直到达到最大值并且是垃圾收集。
这是jstat --gcutil <PID>
的输出,间隔为1秒。关注伊甸园空间E
。
S0 S1 E O M CCS YGC YGCT FGC FGCT GCT
0,00 0,00 67,42 0,00 14,48 17,19 0 0,000 0 0,000 0,000
S0 S1 E O M CCS YGC YGCT FGC FGCT GCT
0,00 0,00 67,42 0,00 14,48 17,19 0 0,000 0 0,000 0,000
# jconsole connected
S0 S1 E O M CCS YGC YGCT FGC FGCT GCT
0,00 96,88 81,64 7,57 92,26 84,87 1 0,001 0 0,000 0,001
S0 S1 E O M CCS YGC YGCT FGC FGCT GCT
0,00 96,88 84,66 7,57 92,26 84,87 1 0,001 0 0,000 0,001
S0 S1 E O M CCS YGC YGCT FGC FGCT GCT
0,00 96,88 89,70 7,57 92,26 84,87 1 0,001 0 0,000 0,001
S0 S1 E O M CCS YGC YGCT FGC FGCT GCT
0,00 96,88 91,70 7,57 92,26 84,87 1 0,001 0 0,000 0,001
S0 S1 E O M CCS YGC YGCT FGC FGCT GCT
0,00 96,88 93,70 7,57 92,26 84,87 1 0,001 0 0,000 0,001
S0 S1 E O M CCS YGC YGCT FGC FGCT GCT
0,00 96,88 95,70 7,57 92,26 84,87 1 0,001 0 0,000 0,001
S0 S1 E O M CCS YGC YGCT FGC FGCT GCT
0,00 96,88 96,70 7,57 92,26 84,87 1 0,001 0 0,000 0,001
S0 S1 E O M CCS YGC YGCT FGC FGCT GCT
0,00 96,88 98,71 7,57 92,26 84,87 1 0,001 0 0,000 0,001
# Garbage collected
S0 S1 E O M CCS YGC YGCT FGC FGCT GCT
100,00 0,00 1,13 14,06 94,75 89,26 2 0,003 0 0,000 0,003
S0 S1 E O M CCS YGC YGCT FGC FGCT GCT
100,00 0,00 3,00 14,06 94,75 89,26 2 0,003 0 0,000 0,003
S0 S1 E O M CCS YGC YGCT FGC FGCT GCT
100,00 0,00 5,75 14,06 94,75 89,26 2 0,003 0 0,000 0,003
正如你所看到的......在jconsole连接到进程之后,eden空间会逐渐增长并生长,直到它被垃圾收集。这导致锯齿形图案。以下是jvisualvm
的快照。
当您对tomcat进程执行相同操作时,您将发现类似的行为。唯一不同的是,即使没有连接jconsole,伊甸园空间也会略微增长。但这种轻微的增长并不是你所看到的锯齿形图案的原因。
这是我的tomcat的jstat
输出。
S0 S1 E O M CCS YGC YGCT FGC FGCT GCT
0,00 99,80 70,33 4,81 96,85 90,10 5 0,037 0 0,000 0,037
S0 S1 E O M CCS YGC YGCT FGC FGCT GCT
0,00 99,80 70,33 4,81 96,85 90,10 5 0,037 0 0,000 0,037
S0 S1 E O M CCS YGC YGCT FGC FGCT GCT
0,00 99,80 70,43 4,81 96,85 90,10 5 0,037 0 0,000 0,037
S0 S1 E O M CCS YGC YGCT FGC FGCT GCT
0,00 99,80 70,43 4,81 96,85 90,10 5 0,037 0 0,000 0,037
S0 S1 E O M CCS YGC YGCT FGC FGCT GCT
0,00 99,80 70,43 4,81 96,85 90,10 5 0,037 0 0,000 0,037
S0 S1 E O M CCS YGC YGCT FGC FGCT GCT
此输出持续36秒,直到您可以看到小内存更改。从70,43
到70,53
。
S0 S1 E O M CCS YGC YGCT FGC FGCT GCT
0,00 99,80 70,43 4,81 96,85 90,10 5 0,037 0 0,000 0,037
S0 S1 E O M CCS YGC YGCT FGC FGCT GCT
0,00 99,80 70,53 4,81 96,85 90,10 5 0,037 0 0,000 0,037
S0 S1 E O M CCS YGC YGCT FGC FGCT GCT
0,00 99,80 70,53 4,81 96,85 90,10 5 0,037 0 0,000 0,037
因此,这个小小的变化是tomcat的后台进程唯一负责的事情。
PS:您还可以不时使用Memory Analyser并获取堆转储,您将看到byte[]
阵列的已用内存量增加,因为RMI网络流量。
答案 1 :(得分:3)
以下是了解链接答案中解释的锯齿形图案的重要观点:
- 当收集器运行时,首先尝试部分收集只释放最近分配的内存
- 最近创建的仍处于活动状态的对象得到了推广&#39;
- 一旦某个对象被提升了几次,即使它已准备好收集,也不会再被部分收集清理
- 这些被称为终身的对象只有在需要完整的集合时才会被清理,以便为程序提供足够的空间来继续运行
问题:即使应用程序完全空闲,导致内存增长的原因是什么?
答案:自动化,计时器等内部预定作业或某些外部进程监控导致内存增长该应用程序闲置。也许您的应用程序具有相同数量的对象,但有些可能更大。例如,您可能有一些ArryList
和一些StrigBuilder
不断增长缓存。
答案 2 :(得分:2)
http://www.oracle.com/technetwork/java/gc-tuning-5-138395.html 首先,这是一个关于“使用5.0 Java TM虚拟机调整垃圾收集”的有用链接
这听起来像GC暂停使tomcat没有响应。开始的一件事是“低暂停”垃圾收集器,带有选项-XX:+ UseConcMarkSweepGC。
答案 3 :(得分:1)
让我们看看图表 大约12:08,工作记忆大小最大(199 MB)。
大约12:09,垃圾收集器工作,收集死对象,工作内存大小约为145 MB。
大约12:12,工作记忆增加,产生了许多死对象,内存从145 MB增加 - &gt; 155 MB - &gt; 165 MB - &gt; 180 MB - &gt; ... - &gt; 190 MB。
大约12:13,垃圾收集器再次运行,收集死对象,工作内存大小约为145 MB。
......等等。 实际上,如果没有特殊事件发生,它是一个周期图。
答案 4 :(得分:1)
原因可能是多种多样的,没有关于您的应用程序的更多信息:假设它自己没有执行任何重复任务,一个可能的原因可能是JConsole本身,因为收集信息并通过RMI发送消耗内存可以从伊甸园空间快速收集。
您可以通过使用较少的&#34;侵入式&#34; 工具进行性能分析来测试此假设(例如,使用-verbosegc
启用GC详细输出)并比较类似的内存使用情况配置文件设置。
正如其他答案所强调的那样,Tomcat也有自己的开销。您可以通过提供&#34; hello,world&#34; servlet并使用类似工具比较两者的内存消耗来测试这个其他假设。