代码之家  ›  专栏  ›  技术社区  ›  Stu Thompson Helter Scelter

为什么sunjvm在堆等大小稳定的情况下仍继续消耗越来越多的RSS内存?

  •  32
  • Stu Thompson Helter Scelter  · 技术社区  · 16 年前

    在过去的一年中,我在我的应用程序的Java堆使用方面做了巨大的改进——减少了66%。为了实现这一点,我一直在通过SNMP监控各种指标,例如Java堆大小、cpu、Java非堆等。

    最近,我一直在监视JVM有多少实际内存(RSS,常驻集),我有点惊讶。JVM消耗的实际内存似乎完全独立于我的应用程序堆大小、非堆、eden空间、线程数等。

    由Java SNMP测量的堆大小 Java Heap Used Graph http://lanai.dietpizza.ch/images/jvm-heap-used.png

    实际内存(KB)。(例如:1MB的KB=1GB) Java Heap Used Graph http://lanai.dietpizza.ch/images/jvm-rss.png

    (堆图中的三个凹陷对应于应用程序更新/重新启动。)

    这对我来说是个问题,因为JVM消耗的所有额外内存都是“窃取”操作系统用于文件缓存的内存。事实上,一旦RSS值达到~2.5-3GB,我就开始看到我的应用程序的响应时间变慢,CPU利用率提高,主要是IO等待。随着交换分区分页的开始。这都是非常不可取的。

    • 为什么会这样?发生了什么事 “引擎盖下”
    • 我可以做些什么来控制JVM的实际内存消耗?

    血淋淋的细节:

    • RHEL4 64位(Linux-2.6.9-78.0.5.ELsmp#1 SMP Wed Sep 24…2008 x86_64…GNU/Linux)
    • Java 6(构建1.6.0_07-b06)
    • 雄猫6
      • 通过java.nio文件通道实现高I/O
      • 数百到数千个线程
      • 数据库使用率低
      • 春天,冬眠

    相关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. 如果有需要编写的内容,该应用程序每15秒更新一次这些JRobin数据库对象。
    4. 在默认配置JRobin中:
      1. 使用 java.nio -基于后端的文件访问。这是一个后端映射 MappedByteBuffers
      2. 每五分钟一次JRobin守护进程线程调用 MappedByteBuffer.force() 在每个JRobin基础数据库MBB上
    5. pmap 上市的:

    最后一点是我的 “尤里卡!” 片刻

    1. 考虑更新到最新的JROBLLITE 1.5.2,这显然是更好的。
    2. 在JRobin数据库上实现适当的资源处理。目前,一旦我的应用程序创建了一个数据库,并且在该数据库不再被有效使用后,再也不会转储它。
    3. 数据库更新事件,而不是定期计时器。这个问题会神奇地消失吗?
    4. 立即 ,将JRobin后端更改为java.io实现——行更改。这将是缓慢的,但它可能不是一个问题。下面的图表显示了这一变化的直接影响。

    Java RSS memory used graph http://lanai.dietpizza.ch/images/stackoverflow-rss-problem-fixed.png

    • JVM内部使用的是什么 MappedByteBuffer.force() ? 如果没有任何更改,它是否仍然写入整个文件?档案的一部分?它是先装的吗?
    • RSS中是否始终存在一定数量的MBB?(RSS大约是总分配MBB大小的一半。巧合?我怀疑不是。)
    • 如果我移动 MappedByteBuffer.force() 要更新数据库事件,而不是定期计时器,问题会神奇地消失吗?
    4 回复  |  直到 6 年前
        1
  •  18
  •   Community Mohan Dere    9 年前

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

    Why does the Sun JVM continue to consume ever more RSS memory even when the heap, etc sizes are stable? ]因为早在2009年,RHEL4就有glibc<2.10 (~2.3)

        2
  •  14
  •   kdgregory    16 年前

    RSS表示正在使用的页面——对于Java,它主要是堆中的活动对象,以及JVM中的内部数据结构。除了使用较少的对象或进行较少的处理外,您无法做很多事情来减小其大小。

    那么,在您的系统中还发生了什么?是不是有很多Tomcat服务器,每台服务器消耗300万RSS?您加入了很多GC标志,它们是否表示进程的大部分时间都在GC中?您是否在同一台计算机上运行数据库?

    根据评论进行编辑

    这让我怀疑你的号码。因此,请运行以下操作以获取快照,而不是一段时间内的图形(用您正在使用的任何进程ID替换7429):

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

    (由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
    

    编辑以向后代解释这些数字

    如上所述,RSS是驻留集大小:物理内存中的页面。SZ持有进程可写的页面数(提交费用);手册页将此值描述为“非常粗略”。VSZ保存进程的虚拟内存映射的大小:可写页面加共享页面。

    详细说明为什么唯一的解决方案是减少对象

    我注意到你提到有几百到几千个线程。这些线程的堆栈也将添加到RSS中,尽管它应该不会太多。假设线程具有较浅的调用深度(典型的应用服务器处理程序线程),每个线程应该只消耗一两页物理内存,即使每个线程的提交费用为半兆。

        3
  •  3
  •   Pascal Thivent    16 年前

    为什么会这样?“引擎盖下”是怎么回事?

    JVM使用的内存不仅仅是堆。例如,Java方法、线程堆栈和本机句柄在内存中与堆以及JVM内部数据结构分开分配。

    关于JNI,您写道应用程序没有使用JNI,但是。。。您使用的是哪种类型的JDBC驱动程序?它可能是2型的,并且有泄漏吗?这是非常不可能的,尽管正如您所说的,数据库使用率很低。

    关于创建过多的线程,每个线程都有自己的堆栈,可能非常大。堆栈大小实际上取决于虚拟机、操作系统和体系结构,例如 JRockit 在Linuxx64上是256K,我在Sun的文档中没有找到Sun VM的参考资料。这直接影响线程内存(线程内存=线程堆栈大小*线程数)。如果创建和销毁大量线程,内存可能无法重用。

    我可以做些什么来控制JVM的实际内存消耗?

    老实说,成百上千的线程对我来说似乎是巨大的。也就是说,如果您确实需要那么多线程,那么可以通过 -Xss

        4
  •  1
  •   jarnbjo    16 年前

    众所周知,Java中当前的垃圾收集器不会释放分配的内存,尽管不再需要内存。然而,非常奇怪的是,您的RSS大小增加到>3GB,尽管堆大小限制为640MB。您是在应用程序中使用任何本机代码,还是启用了Tomcat本机性能优化包?在这种情况下,您的代码或Tomcat中当然可能存在本机内存泄漏。