在过去的一年中,我在应用程序的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
我如何衡量RSS:
ps x -o command,rss | grep java | grep latest | cut -b 17-
这将进入一个文本文件,并定期将其读入监视系统的RRD数据库中。注意ps输出千字节。
虽然它到底是 ATorras
的答案被证明最终是正确的,它
kdgregory
谁引导我与使用的正确诊断路径pmap
。(去投票给他们两个答案!)这是正在发生的事情:
我肯定知道的事情:
java.nio
基于文件的后端访问。该后端映射MappedByteBuffers
到文件本身。MappedByteBuffer.force()
在每个JRobin基础数据库MBB上调用pmap
列出:
最后一点是我的 “尤里卡!” 时刻。
我的纠正措施:
MappedByteBuffer.force()
到数据库更新事件,而不要使用定期计时器。问题会神奇地解决吗?Java RSS内存使用图http://lanai.dietpizza.ch/images/stackoverflow-rss-problem-
fixed.png
我可能没有时间想出的问题:
MappedByteBuffer.force()
什么?如果没有任何变化,它是否仍会写入整个文件?文件的一部分?它首先加载吗?MappedByteBuffer.force()
到数据库更新事件,而不是使用定期计时器,问题会神奇地消失吗?只是一个想法:NIO缓冲区位于JVM外部。
编辑: 根据2016年,值得考虑@Lari Hotari评论即使堆等大小稳定时,为什么Sun
JVM仍继续消耗更多的RSS内存?,因为回到2009年,RHEL4的glibc <2.10(〜2.3)
为什么会这样呢?“幕后”发生了什么?
JVM使用的内存不仅仅是堆。例如,Java方法,线程堆栈和本机句柄与堆以及JVM内部数据结构分开分配在内存中。
在您的情况下,可能的麻烦原因可能是:NIO(已经提到),JNI(已经提到),过多的线程创建。
关于JNI,您曾写道该应用程序未使用JNI,但是…您正在使用哪种类型的JDBC驱动程序?可能是2型泄漏吗?但是,正如您所说的那样,数据库使用率很低是非常不可能的。
关于过多的线程创建,每个线程都有自己的堆栈,该堆栈可能很大。堆栈大小实际上取决于VM,OS和体系结构,例如对于JRockit,Linux x64上的堆栈大小为256K,我在Sun文档中没有找到有关Sun VM的参考。这直接影响线程内存(线程内存=线程堆栈大小*线程数)。而且,如果您创建和销毁大量线程,则内存可能不会被重用。
如何控制JVM的实际内存消耗?
老实说,对我而言,成百上千的线程似乎是巨大的。也就是说,如果您确实需要那么多线程,则可以通过该-Xss选项配置线程堆栈大小。这样可以减少内存消耗。但是我认为这不会解决整个问题。我倾向于认为当我查看实际内存图时,某处会有泄漏。
问候。
我为我的Java web应用程序分配了一个最大值。由于一些内存泄漏,应用程序已经消耗了将近2 GB的分配内存。此时,我已经使用进行了内存转储。在一个实例中,堆转储大小接近>1.5GB,而在另一个实例中,堆转储大小<100 MB。这背后的原因是什么?
我们将和设置为1536m。现在,如果我理解正确的话,j-xmx表示堆的最大大小。 本系统采用4核15GB ram进程。 但是,当我检查正在运行的Java进程的RSS(使用top)时,我看到它使用的值比大,大约。 对于来说,有4个内核和15GB RAM的理想设置是什么(假设除了Java应用程序之外,系统中没有其他进程在运行)
问题内容: 我们正试图在我们的Web应用程序中找到导致大量内存泄漏的元凶。我们在发现内存泄漏方面经验有限,但是我们发现了如何使用Eclipse MAT进行Java堆转储并对其进行分析。 但是,对于我们使用56 / 60GB内存的应用程序,堆转储的大小仅为16GB,而在Eclipse MAT中则更少。 语境 我们的服务器将Ubuntu 14.04上的Wildfly 8.2.0用于我们的Java应用程
我们正试图找到web应用程序中大内存泄漏的罪魁祸首。我们在查找内存泄漏方面的经验相当有限,但我们了解了如何使用创建java堆转储,并在Eclipse mat中对其进行分析。 但是,由于我们的应用程序使用56/60GB内存,堆转储的大小只有16GB,在Eclipse mat中就更少了。 对于我们的java应用程序,我们的服务器使用Ubuntu14.04上的Wildfly8.2.0,其进程使用了95%
问题内容: 该表包含大约一千万行。 这会导致内存使用量稳定增加到4 GB左右,这时行将快速打印。第一行打印之前漫长的延迟使我感到惊讶–我希望它几乎可以立即打印。 我也尝试过以相同的方式表现。 我不知道Django将什么加载到内存中或为什么这样做。我希望Django在数据库级别遍历结果,这意味着结果将以大致恒定的速率打印(而不是经过漫长的等待一次全部打印)。 我误会了什么? (我不知道它是否相关,但
问题内容: 这是 不是 增加Java的堆的最大尺寸的虚拟机启动后。技术原因是什么?垃圾回收算法是否取决于要使用固定数量的内存?还是出于安全原因,通过消耗所有可用内存来防止Java应用程序从DOS的系统中移至其他应用程序? 问题答案: 最后我知道在Sun的JVM中,必须在连续的地址空间中分配整个堆。我想对于大堆值,很难在启动后将其添加到您的地址空间中,同时又要确保它保持连续。您可能需要在启动时获取它