Java进程内存远远大于指定的限制

Java进程内存远远大于指定的限制,java,linux,memory,process,Java,Linux,Memory,Process,我已经研究了大多数可用的方法,以了解java进程到底使用了多少内存。 到目前为止,我可以说我知道分配的总内存可能是以下一个或多个: 堆内存(假定由my-XX:MaxHeapSize=4096m控制) 永久内存(假定由my-XX:MaxPermSize=1024m控制) 保留代码缓存(假定由my-XX:ReservedCodeCacheSize=256m控制) N个线程*线程大小(假定由my-XX:ThreadStackSize=1024控制) 但是结果与linux告诉我的太不一样了,我发现任

我已经研究了大多数可用的方法,以了解java进程到底使用了多少内存。 到目前为止,我可以说我知道分配的总内存可能是以下一个或多个:

  • 堆内存(假定由my-XX:MaxHeapSize=4096m控制)
  • 永久内存(假定由my-XX:MaxPermSize=1024m控制)
  • 保留代码缓存(假定由my-XX:ReservedCodeCacheSize=256m控制)
  • N个线程*线程大小(假定由my-XX:ThreadStackSize=1024控制)
但是结果与linux告诉我的太不一样了,我发现任何一种方法都可以获得java进程的内存消耗

在我的例子中,它是一个运行在Ubuntu 11.10 x86_64机器上的Tomcat实例,JVM 1.6_26 64位,并且
ps-ALcf | grep org.apache.catalina.startup.Bootstrap | wc-l
告诉我有145个线程或进程正在运行,它们都链接到同一根进程(Tomcat)

所有的总结应该给我最大的记忆 (4096MB)+(1024MB)+(256MB)+145*(1024KB)=5521MB。
jmap-heap-PID
告诉我的是,ManagementFactory.memoryMXBean.(heapMemoryUsage+nonHeapMemoryUsage).getCommitted()告诉我的是什么,上面的理论值都是成对的

现在到linux端,
top
nmon
都告诉我这个进程分配的剩余内存是5.8GB->大约5939,2MB。但我也知道这只是内存的一部分,在实时RAM内存中。VIRT by
top
和Size by
nmon
(两者都应该表示相同)告诉我该过程是7530MB(或者确切地说是7710952KB by
nmon
)。 这与预期的最大值相差太大:比最大值高出2009MB,而且根据jmap和jstat,堆内存分配甚至没有达到峰值(2048 OldSpace+1534-Eden+)

top
还告诉我,代码堆栈是36KB(对于最初的catalina初学者来说还算合理),数据堆栈是7.3GB(代表其余部分)

这个tomcat服务器实例是这台机器上唯一运行的实例,并且一直存在一些不稳定性。需要每三天左右重新启动一次,因为机器有7647544k RAM可用,并且没有交换(出于性能原因)。我对限制进行了计算,并期望流程遵循这些限制,我发现为机器上运行的所有其他服务留出了相当好的安全余量(除了ssh和top本身之外,没有其他服务会麻烦):7468-5521=1947。这对于“安全边际”来说几乎是太多了

所以,我想知道所有的记忆是从哪里来的,为什么没有遵守限制。如果缺少任何信息,我很乐意提供。

下面是一个例子,它不像根据你在问题中的假设所期望的那样简单,它非常值得一读

许多实现中的线程堆栈大小都有最小限制,这些限制因操作系统和JVM版本而异;如果将限制设置为低于JVM或OS的本机操作系统限制(有时必须设置ulimit on*nix),则会忽略threadstack设置。其他命令行选项的工作方式与此相同,当提供的值太小时,默认默认为较高的值。不要假设传入的所有值都表示实际使用的值

类加载器和Tomcat不止一个,占用了大量不易记录的内存。JIT消耗了大量内存,以空间换取时间,这在大多数情况下都是一种很好的折衷


您引用的数字与我的预期非常接近。

虚拟内存是使用的地址空间量,这一点我不会太在意,因为您有一个64位应用程序。常驻内存是实际使用的主内存量

您可以添加到您的列表中

  • 包括JVM在内的共享库~0.5克
  • 直接内存(0到4G)默认情况下,最大值与堆最大值相同
  • 内存映射文件。没有限制
您可以执行
pmap
来显示有多少地址空间用于什么目的


顺便说一句:由于内存映射文件,我的进程在顶部显示640G VIRT。它可以比住户的规模大很多

在顶部的分解图中,您忘了提到JNI在堆外分配内存。您正在评测的应用程序是否可能正在使用JNI?我不知道是否有办法确定(是否存在?),但我认为这不是从我对整个应用程序的了解中得出的。至少我可以保证它没有明确的用途。应用程序连接到外部数据库(不在同一台机器上),不知道是否可以直接使用JNI。无论如何,整个池的缓存在另一端,在数据库端,所以不应该计数。RSS的可能重复与java堆不同。VIRT包括MMAMED文件感谢您的澄清和链接,但我仍然无法接受约36%的额外内存,因为我无法直接控制“我所期望的”。无论如何,再次感谢您,我现在有一些关于如何根据我在这个java进程上所做的一些其他配置来降低这个数字的提示。除此之外,关于XX:MaxDirectMemorySize还有什么要说的吗?弄乱这个设置可能会导致更多的问题。与JVM的其余部分相比,这是微不足道的,更不用说基于Tomcat的应用程序了。