-->

为什么太阳JVM继续消耗,即使堆等尺寸稳定更加RSS内存?(Why does the Sun JVM

2019-08-31 16:37发布

扎实减少66% - 在过去的一年我在我的应用程序的Java堆的使用取得了巨大的改进。 在追求的,我一直在监测各种指标,如Java堆大小,CPU,Java的非堆等通过SNMP。

最近,我一直在监测由JVM多少实际内存(RSS,常驻集),并感到有点惊讶。 由JVM实际消耗的记忆似乎完全独立的我的应用程序堆大小,非堆,伊甸园空间,线程数等。

由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等待。 由于一些点分页到swap分区踢,这是非常不可取的。

所以,我的问题:

  • 这究竟是为什么? 这是怎么回事“引擎盖下”?
  • 我能做些什么来保持JVM真实的内存消耗在检查?

血淋淋的细节:

  • RHEL4 64位(Linux的 - 2.6.9-78.0.5.ELsmp#1 SMP周三09月24日... 2008 ... x86_64的GNU / Linux的)
  • Java 6中(建1.6.0_07-B06)
  • Tomcat的6
  • 应用程序(按需HTTP视频流)
    • 高I ​​/ O通过java.nio中FileChannels
    • 数百到数千低线程
    • 低使用数据库
    • spring,hibernate的

有关JVM参数:

-Xms128m  
-Xmx640m  
-XX:+UseConcMarkSweepGC  
-XX:+AlwaysActAsServerClassMachine  
-XX:+CMSIncrementalMode    

-XX:+PrintGCDetails 
-XX:+PrintGCTimeStamps  
-XX:+PrintGCApplicationStoppedTime  
-XX:+CMSLoopWarn  
-XX:+HeapDumpOnOutOfMemoryError 

如何我衡量RSS:

ps x -o command,rss | grep java | grep latest | cut -b 17-

这正好到一个文本文件,并读入RRD数据库定期我的监控系统。 需要注意的是ps的输出千字节。


存在的问题及解决方案S:

虽然它到底是ATorras的答案被证明最终是正确的,它kdgregory谁引导我与使用的正确诊断路径pmap 。 (去投票了两个自己的答案!)这是发生了什么事:

事情我肯定知道:

  1. 我的应用程序记录和显示数据与JRobin 1.4 ,这是我在三年前编码到我的应用程序。
  2. 应用程序的最繁忙的实例:当前创建
    1. 在1000启动的一个小时内,一些新的JRobin数据库文件(约1.3MB每个)
    2. 〜100 +在启动后的每一天
  3. 该应用程序更新这些JRobin数据库对象每隔15秒,如果有东西可写。
  4. 在默认配置JRobin:
    1. 使用java.nio基于文件访问后端。 这后端映射MappedByteBuffers到文件本身。
    2. 每五分钟一次JRobin守护线程调用MappedByteBuffer.force()每JRobin基础数据库对MBB
  5. pmap所示:
    1. 6500个映射
    2. 其中5500人1.3MB JRobin数据库文件,其中工程出来〜7.1GB

最后一点是我“找到了!” 时刻。

我纠正措施:

  1. 考虑更新到这显然是更好的最新JRobinLite 1.5.2
  2. 在JRobin数据库实施适当的资源处理。 目前,一旦我的应用程序创建一个数据库,然后从不转储数据库的数据库不再积极地使用了。
  3. 实验与移动MappedByteBuffer.force()数据库更新事件,而不是一个周期性的计时器。 将这个问题奇迹般地消失?
  4. 随即 ,改变JRobin后端的java.io执行-线换线。 这会慢一些,但它可能不是一个问题。 这里是在这种变化的直接影响的图表。

Java的RSS内存使用图形http://lanai.dietpizza.ch/images/stackoverflow-rss-problem-fixed.png

我可能会或可能不会有时间问题搞清楚:

  • 什么是JVM内部发生的事情与MappedByteBuffer.force() 如果一切都没有改变,它仍然写整个文件? 该文件的一部分? 它首先加载它?
  • 有没有在任何时候总是在RSS一定量的MBB的? (RSS大约一半分配MBB尺寸。巧合吗?我怀疑不是总有人。)
  • 如果我移动MappedByteBuffer.force()数据库更新事件,而不是一个周期定时器,将这个问题奇迹般地消失?
  • 为什么是RSS坡所以定期? 它不关联到任何应用负载的指标。

Answer 1:

只是一个想法:NIO缓冲区被放置在JVM之外。

编辑:按照2016这是值得考虑@Lari Hotari评论[ 为什么太阳JVM继续消耗,即使堆等尺寸稳定更加RSS内存? ]因为追溯到2009年,有RHEL4的glibc <2.10(〜2.3)

问候。



Answer 2:

RSS表示正在积极使用的页面 - 针对Java,它主要是在堆中活动的对象,并在JVM内部数据结构。 有没有什么可以做,以减少它的大小,除了使用更少的对象或者少做处理。

在你的情况,我不认为这是一个问题。 该图似乎显示3 MEG消费,而不是3演出,你在文中写道。 这是非常小的,而且是不太可能导致分页。

所以,还有什么在你的系统是怎么回事? 难道,你有很多的Tomcat服务器的情况下,RSS的每消耗3M? 你扔了很多GC的标志,没有表明该过程花费其大部分时间在GC? 你有在同一台机器上运行的数据库?

编辑回应评论

关于3M RSS大小 - 是啊,这似乎太低了Tomcat进程(我检查我的盒子,并有一个在89M尚未活跃了一段时间)。 不过,我并不指望它>堆大小,我当然不希望它是近5倍堆大小(你使用-Xmx640) - 它应该在最坏的情况是堆的大小+一些每个应用不变。

这使我怀疑你的号码。 因此,而不是随时间的曲线图,请执行下列以获得快照(通过任何进程ID您正在使用替代7429):

ps -p 7429 -o pcpu,cutime,cstime,cmin_flt,cmaj_flt,rss,size,vsize

(由斯图编辑,所以我们可以有格式化的结果为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

编辑解释这些数字为后人

RSS,如上所述,是驻留集大小:在物理内存中的页面。 SZ持有由过程可写页(提交电荷)的数量; 手册页描述了这个值作为“非常粗糙”。 VSZ保持虚拟存储器映射的处理的大小:可写页加上共享页。

通常情况下,VSZ略有> SZ,并非常> RSS。 这个输出表明一个非常不寻常的情况。

阐述为什么唯一的解决办法是减少对象

RSS代表的居民在RAM中的页面数 - 正在积极访问的网页。 在Java中,垃圾回收器会定期遍历整个对象图。 如果这个对象图占据了大部分的堆空间,那么收集器将触摸堆中每一个页面,要求所有的页面成为内存驻留。 GC为约每一个主要收集后压实堆非常好,所以如果你有偏堆运行,所以大部分的网页不应该需要在RAM中。

还有一些其他的选择

我注意到,你提到有几百到低数千个线程。 这些线程堆栈也将增加RSS,虽然它不应该太大。 假设线程有一个浅调用深度(通常用于应用服务器处理线程),每次只消耗一两页的物理内存,即使有一个半兆承诺费为每。



Answer 3:

这究竟是为什么? 这是怎么回事“引擎盖下”?

JVM使用更多的内存比刚堆。 例如Java方法,线程堆栈和本机手柄在存储器从堆中,以及JVM内部数据结构独立的分配。

对你来说,烦恼的可能原因是:NIO(已经提到),JNI(已经提到),过多的线程创建。

关于JNI,你写的应用程序没有使用您正在使用什么类型的JDBC驱动程序的JNI但是......? 难道是一个类型2,和泄漏? 正如你所说的数据库使用的是低这不太可能,但。

关于过度创建线程,每个线程都有自己的堆栈,它可能是相当大的。 堆栈大小实际上取决于虚拟机,操作系统和架构例如用于JRockit的是256K在Linux x64上,我没有找到Sun的Sun公司的虚拟机文件中的参考。 直接这会影响该线程存储器(线程存储器=线程堆栈大小*线程数)。 如果你创建和销毁大量的线程,内存可能不会重用。

我能做些什么来保持JVM真实的内存消耗在检查?

说实话,数百低数千个线程似乎巨大的给我。 也就是说,如果你真的需要这么多线程,该线程堆栈大小可以通过配置-Xss选项。 这可以减少内存消耗。 但我不认为这将解决整个问题。 我倾向于认为,有泄漏的地方,当我看到真实的记忆曲线。



Answer 4:

Java当前的垃圾收集器是众所周知的,不释放分配的内存,虽然内存不再需要。 这是相当奇怪不过,您的RSS尺寸增大到> 3GB虽然堆大小限制为640MB。 您使用的应用程序中的任何本地代码或者是你有Tomcat的原生性能优化包启用? 在这种情况下,你当然可以在你的代码或Tomcat的本机内存泄漏。

使用Java 6u14,Sun推出了新的“垃圾第一”的垃圾收集器,这是能够,如果它不再需要释放内存回操作系统。 它仍然归类为实验而不是默认启用的,但如果它是一个可行的选择你,我会尝试升级到最新的Java 6的发布,使用命令行参数“-XX新的垃圾收集器:+ UnlockExperimentalVMOptions - XX:+ UseG1GC”。 它可能会解决你的问题。



文章来源: Why does the Sun JVM continue to consume ever more RSS memory even when the heap, etc sizes are stable?