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

Java 为什么sunjvm在堆等大小稳定的情况下仍继续消耗越来越多的RSS内存?,java,memory,jvm,sun,performance,Java,Memory,Jvm,Sun,Performance,在过去的一年中,我在我的应用程序的Java堆使用方面做了巨大的改进——减少了66%。为了实现这一点,我一直在通过SNMP监控各种指标,例如Java堆大小、cpu、Java非堆等 最近,我一直在监视JVM有多少实际内存(RSS,常驻集),我有点惊讶。JVM消耗的实际内存似乎完全独立于我的应用程序堆大小、非堆、eden空间、线程数等 由Java SNMP测量的堆大小 实际内存(KB)。(例如:1MB的KB=1GB) (堆图中的三个凹陷对应于应用程序更新/重新启动。) 这对我来说是个问题,因为JV

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

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

由Java SNMP测量的堆大小

实际内存(KB)。(例如:1MB的KB=1GB)

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

这对我来说是个问题,因为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
  • 应用程序(按需HTTP视频流)
    • 通过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输出千字节


问题与解决方案: 虽然最终证明是的答案最终是正确的,但是通过使用
pmap
引导我找到了正确的诊断路径。(去投票支持他们的两个答案!)下面是发生的事情:

我肯定知道的事情:

  • 我的应用程序记录和显示数据,这是我三年前在应用程序中编写的代码
  • 当前创建的应用程序最繁忙的实例
  • 启动后一小时内,超过1000个新的JRobin数据库文件(每个文件大约1.3MB)
  • 启动后每天约100多人
  • 如果有需要编写的内容,该应用程序每15秒更新一次这些JRobin数据库对象
  • 在默认配置JRobin中:
  • 使用基于
    java.nio
    的文件访问后端。此后端将
    mappedbytebuffer
    映射到文件本身
  • 每五分钟一次,JRobin守护程序线程在每个JRobin基础数据库MBB上调用
    MappedByteBuffer.force()
  • pmap
    列出:
  • 6500映射
  • 其中5500个是1.3MB的JRobin数据库文件,计算起来约为7.1GB
  • 最后一点是我的“尤里卡”时刻

    我的纠正措施:

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

    • 使用
      MappedByteBuffer.force()
      ,JVM内部发生了什么?如果没有任何更改,它是否仍然写入整个文件?档案的一部分?它是先装的吗
    • RSS中是否始终存在一定数量的MBB?(RSS大约是总分配MBB大小的一半。巧合?我怀疑不是。)
    • 如果我将
      MappedByteBuffer.force()
      移动到数据库更新事件,而不是定期计时器,问题会神奇地消失吗
    • 为什么RSS坡度如此规则?它与任何应用程序负载度量都不相关

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

    对你来说,我不认为这是个问题。当您在文本中写入时,图表显示消耗了3兆,而不是3千兆。这真的很小,不太可能导致分页

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

    根据评论进行编辑

    关于3M RSS的大小——是的,这对于Tomcat进程来说似乎太小了(我选中了我的框,有一个89M的RSS已经有一段时间没有激活了)。然而,我不一定期望它是>堆大小,我当然也不期望它几乎是堆大小的5倍(您使用-Xmx640)——最坏的情况下,它应该是堆大小+每个应用程序的一些常量

    这让我怀疑你的号码。因此,请运行以下命令,而不是一段时间内的图形,以获取快照(用whatev替换7429
    ps -p 7429 -o pcpu,cutime,cstime,cmin_flt,cmaj_flt,rss,size,vsize
    
    [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