在HP-UX环境JVM中C堆与Java堆中运行的是什么?
在HP-UX环境中,某些Java应用程序一直遇到一个特殊的问题。
堆设置为-mx512,但是,使用gpm查看此java进程的内存区域,它显示使用了1.6GB以上的RSS内存,并为DATA区域分配了1.1GB。在24-48小时内增长非常迅速,然后大幅放缓,仍然每隔几个小时增长2MB。但是,Java堆没有显示泄漏的迹象。
好奇如何做到这一点,我研究了一下,发现了有关HP在Java堆和C堆中的内存泄漏的文章:http://docs.hp.com/en/JAVAPERFTUNE/Memory-Management.pdf
我的问题是什么决定C堆与Java堆中运行的内容,对于未通过Java堆运行的事物,我们将如何识别正在C堆上运行的那些对象?另外,java堆是否位于C堆内部?
解决方案
回答
我对给出的数字的唯一猜测是Java VM中的内存泄漏。我们可能要尝试在我们引用的论文中列出的其他VM之一。另一个(要困难得多)的替代方法可能是在HP平台上编译开放的Java。
Sun的Java尚未100%开放,他们正在开发它,但是我相信sourceforge中有一个。
Java也顺便破坏了内存。有时,这会使操作系统内存管理有些混乱(当Windows内存不足并要求Java释放一些内存时,我们会看到它,Java触摸了所有对象,导致它们从交换文件中加载,Windows痛苦地尖叫着,死了)。我认为那不是我们所看到的。
回答
通常,只有Java对象中的数据存储在Java堆上,Java VM所需的所有其他内存都是从"本机"或者" C"堆分配的(实际上,Java堆本身只是分配的一个连续块从C堆)。
由于JVM要求Java堆(如果正在使用世代垃圾回收,则是堆)是连续的内存,因此通常在JVM启动时分配整个最大堆大小(-mx值)。在实践中,Java VM将尝试最小化对该空间的使用,以使操作系统不需要为其保留任何实际内存(操作系统足够脆弱,无法知道何时从未写入存储空间) 。
因此,Java堆将在内存中占用一定数量的空间。
其余的存储将由Java VM和任何正在使用的JNI代码使用。例如,JVM需要内存来存储Java字节码和已加载类的常量池,JIT编译后的代码的结果,用于编译JIT代码的工作区,本机线程堆栈和其他此类杂物。
JNI代码只是特定于平台的(编译)C代码,可以使用"本机"方法的形式绑定到Java对象。当执行此方法时,绑定的代码将被执行,并且可以使用标准的C例程(例如malloc)分配内存,这将消耗C堆上的内存。
回答
考虑一下组成Java进程的东西。
你有:
- JVM(C程序)
- JNI数据
- Java字节码
- Java数据
值得注意的是,它们都生活在C堆中(JVM堆自然是C堆的一部分)。
在Java堆中,只是Java字节码和Java数据。但是Java堆中也有"可用空间"。
典型的(即Sun)JVM仅根据需要增加Java Heap,而不会缩小它。一旦达到定义的最大值(-Xmx512M),它就会停止增长并处理剩下的所有内容。当最大堆耗尽时,我们将获得OutOfMemory异常。
Xmx512M选项不做的事情是限制进程的整体大小。它仅限制了该过程中的Java Heap部分。
例如,我们可能有一个人为设计的Java程序,该程序使用10mb的Java堆,但是调用了分配500MB C堆的JNI调用。即使Java堆很小,我们也可以看到进程大小如何。同样,使用新的NIO库,我们也可以在堆外部添加内存。
我们必须考虑的另一方面是Java GC通常是" Copying Collector"。这意味着它将从正在收集的内存中获取"实时"数据,并将其复制到内存的其他部分。至少从Xmx参数而言,复制到的此空白空间不是堆的一部分。就像"新堆"一样,在复制后成为堆的一部分(旧空间用于下一个GC)。如果我们有一个512MB的堆,而该堆的大小为510MB,则Java将在某个位置复制实时数据。天真的想法是去另一个大的开放空间(例如500 + MB)。如果所有数据都是"实时"的,那么将需要一大块复制到其中。
因此,我们可以看到,在最极端的情况下,我们至少需要使系统上的可用内存增加一倍才能处理特定的堆大小。 512MB堆至少1GB。
事实证明,实际情况并非如此,并且内存分配等要复杂得多,但是我们确实需要大量可用内存来处理堆副本,这会影响整个进程的大小。
最后,请注意,JVM做一些有趣的事情,例如将rt.jar类中的映射映射到VM以简化启动。它们映射在只读块中,并且可以在其他Java进程之间共享。这些共享页面将"计数"所有Java进程,即使它实际上只消耗一次物理内存(虚拟内存的魔力)。
现在,为什么进程继续增长,如果我们从未遇到过Java OOM消息,这意味着泄漏不在Java堆中,但这并不意味着它可能不在其他地方(JRE运行时,第三方JNI库,本机JDBC驱动程序等)。