考虑构成Java过程的是什么。
您有:
- 的JVM(一个C程序)
- JNI数据
- Java字节码
- Java数据
值得注意的是,他们都住在C堆(JVM堆自然是C堆的一部分)。
在Java堆是简单地JAVA字节代码和Java数据。但Java堆中还有什么是“自由空间”。
典型的(即Sun)JVM只根据需要增长Java堆,但永远不会缩小它。一旦达到其定义的最大值(-Xmx512M),它会停止增长并处理剩下的任何事情。当这个最大堆耗尽时,你会得到OutOfMemory异常。
什么是Xmx512M选项不这样做,是限制进程的总体规模。它仅限制进程的Java堆部分。例如,您可能有一个人为的Java程序,它使用10MB的Java堆,但调用分配500MB C堆的JNI调用。即使Java堆很小,您也可以看到您的进程大小如何。另外,使用新的NIO库,您还可以在堆外部附加内存。
,你必须考虑的另一个方面是,Java的GC是典型的“复制收集器”。这意味着需要从内存中收集“实时”数据,并将其复制到另一部分内存中。这个空的空间复制到IS NOT PART OF HEAP,至少不是Xmx参数。它就像“新堆”一样,并且在副本之后成为堆的一部分(旧空间用于下一个GC)。如果你有一个512MB的堆,而且它的容量是510MB,那么Java将会把实时数据复制到某个地方。天真的想法是到另一个大的开放空间(如500 + MB)。如果你的所有数据都是“活的”,那么它需要一个大块来复制。
因此,您可以看到,在最极端的情况下,您至少需要将系统上的可用内存翻倍以处理特定的堆大小。 512MB堆至少1GB。
原来,实际情况并非如此,内存分配等比这更复杂,但您确实需要大量的可用内存来处理堆副本,并且这会影响整个进程大小。
最后,请注意JVM执行有趣的事情,如在rt.jar类中映射到VM以简化启动。它们映射在只读块中,并可以在其他Java进程中共享。这些共享页面将对所有Java进程进行“计数”,即使它实际上只消耗一次物理内存(虚拟内存的魔力)。
现在至于为什么你的进程继续增长,如果你从未击中Java OOM消息,那意味着你的泄漏不在Java堆中,但这并不意味着它可能不在其他东西中JRE运行时,第三方JNI库,本地JDBC驱动程序等)。