Stu*_*son 33 java memory performance jvm sun
在过去的一年里,我在应用程序的Java堆使用方面做了很大的改进 - 减少了66%.为此,我一直在通过SNMP监控各种指标,例如Java堆大小,cpu,Java非堆等.
最近,我一直在监视JVM有多少实内存(RSS,驻留集)并且有点惊讶.JVM消耗的实际内存似乎完全独立于我的应用程序堆大小,非堆,eden空间,线程数等.
堆栈大小由Java SNMP Java堆使用图表测量http://lanai.dietpizza.ch/images/jvm-heap-used.png
以KB为单位的实内存.(例如:1 MB KB = 1 GB) Java堆使用图http://lanai.dietpizza.ch/images/jvm-rss.png
(堆图中的三个凹陷对应于应用程序更新/重新启动.)
这对我来说是一个问题,因为JVM正在消耗的所有额外内存都是"窃取"内存,可供操作系统用于文件缓存.实际上,一旦RSS值达到~2.5-3GB,我开始看到响应时间变慢,应用程序的CPU利用率更高,主要是IO等待.正如某些点对交换分区的分页启动.这都是非常不受欢迎的.
所以,我的问题:
血腥的细节:
相关的JVM参数:
-Xms128m
-Xmx640m
-XX:+UseConcMarkSweepGC
-XX:+AlwaysActAsServerClassMachine
-XX:+CMSIncrementalMode
-XX:+PrintGCDetails
-XX:+PrintGCTimeStamps
-XX:+PrintGCApplicationStoppedTime
-XX:+CMSLoopWarn
-XX:+HeapDumpOnOutOfMemoryError
Run Code Online (Sandbox Code Playgroud)
我如何衡量RSS:
ps x -o command,rss | grep java | grep latest | cut -b 17-
Run Code Online (Sandbox Code Playgroud)
这将进入一个文本文件,并定期读入我的监控系统的RRD数据库.请注意,ps输出Kilo Bytes.
虽然最终是ATorras的答案证明最终是正确的,但是kdgregory通过使用引导我到正确的诊断路径pmap
.(对他们的答案进行投票!)以下是发生的事情:
我确切知道的事情:
java.nio
基于文件的访问后端.此后端映射MappedByteBuffers
到文件本身.MappedByteBuffer.force()
一次JRobin底层数据库MBBpmap
上市:
最后一点是我的"尤里卡!" 时刻.
我的纠正措施:
MappedByteBuffer.force()
到数据库更新事件,而不是定期计时器.这个问题会神奇地消失吗?Java RSS内存使用图http://lanai.dietpizza.ch/images/stackoverflow-rss-problem-fixed.png
我可能有或没有时间弄清楚的问题:
MappedByteBuffer.force()
什么?如果没有任何改变,它是否仍然写入整个文件?部分文件?它首先加载吗?MappedByteBuffer.force()
到数据库更新事件,而不是定期计时器,问题会神奇地消失吗?ATo*_*ras 18
只是一个想法:NIO缓冲区放在JVM之外.
编辑: 按照2016年值得考虑@Lari Hotari评论[ 为什么Sun JVM继续消耗更多的RSS内存,即使堆等大小稳定?]因为回到2009年,RHEL4的glibc <2.10(~2.3)
问候.
kdg*_*ory 14
RSS表示正在使用的页面 - 对于Java,它主要是堆中的活动对象,以及JVM中的内部数据结构.除了使用更少的对象或更少的处理之外,你可以做很多事情来减小它的大小.
在你的情况下,我不认为这是一个问题.当您在文本中写入时,图表似乎显示消耗3兆,而不是3演出.这真的很小,不太可能导致分页.
那么你的系统还发生了什么呢?是否存在大量Tomcat服务器,每个服务器消耗3M的RSS?你投入了很多GC标志,它们是否表明该过程大部分时间都花在了GC上?你有在同一台机器上运行的数据库吗?
编辑以回应评论
关于3M RSS大小 - 是的,对于Tomcat进程来说这似乎太低了(我检查了我的盒子,并且在89M处有一个没有活动一段时间).不过,我并不指望它>堆大小,我当然不希望它是近5倍堆大小(你使用-Xmx640) - 它应该在最坏的情况是堆的大小+一些每个应用不变.
这让我怀疑你的号码.因此,请运行以下内容以获取快照(使用您正在使用的任何进程ID替换7429),而不是随时间变化的图表:
ps -p 7429 -o pcpu,cutime,cstime,cmin_flt,cmaj_flt,rss,size,vsize
Run Code Online (Sandbox Code Playgroud)
(由Stu编辑,所以我们可以将结果格式化为上述ps信息请求:)
[stu@server ~]$ ps -p 12720 -o pcpu,cutime,cstime,cmin_flt,cmaj_flt,rss,size,vsize
%CPU - - - - RSS SZ VSZ
28.8 - - - - 3262316 1333832 8725584
Run Code Online (Sandbox Code Playgroud)
编辑为后代解释这些数字
如上所述,RSS是驻留集大小:物理内存中的页面.SZ保存进程可写的页数(提交费用); 该联机帮助页将此值描述为"非常粗糙".VSZ保存进程的虚拟内存映射的大小:可写页面和共享页面.
通常,VSZ略微> SZ,非常> RSS.此输出表明非常不寻常的情况.
详细说明为什么唯一的解决方案是减少对象
RSS表示驻留在RAM中的页面数 - 主动访问的页面.使用Java,垃圾收集器将定期遍历整个对象图.如果此对象图占用了大部分堆空间,则收集器将触及堆中的每个页面,从而要求所有这些页面都成为驻留在内存中的页面.GC非常适合在每个主要集合之后压缩堆,因此如果你使用部分堆运行,那么大多数页面都不需要在RAM中.
还有其他一些选择
我注意到你提到有数百到数千个线程.这些线程的堆栈也会添加到RSS中,尽管它不应该太多.假设线程有一个浅调用深度(通常用于应用服务器处理线程),每次只消耗一两页的物理内存,即使有一个半兆承诺费为每.
归档时间: |
|
查看次数: |
10816 次 |
最近记录: |