zxc*_*xcv 2 c java jvm hp-ux heap-memory
我在 HP-UX 环境中遇到了某些 Java 应用程序的特殊问题。
堆被设置为 -mx512,然而,使用 gpm 查看这个 java 进程的内存区域,它显示它使用了超过 1.6GB 的 RSS 内存,其中 1.1GB 分配给了数据区域。在 24-48 小时内增长得非常快,然后大幅放缓,每几个小时仍然增长 2MB。但是,Java 堆没有泄漏的迹象。
好奇这是怎么可能的,我研究了一下,发现了这篇关于 java 堆和 c 堆内存泄漏的惠普文章:http : //docs.hp.com/en/JAVAPERFTUNE/Memory-Management.pdf
我的问题是什么决定了在 C 堆和 Java 堆中运行的内容,对于不通过 Java 堆运行的内容,您将如何识别在 C 堆上运行的那些对象?另外java堆是否位于C堆内?
考虑是什么组成了 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 通常是一个“复制收集器”。这意味着它从它收集的内存中获取“实时”数据,并将其复制到内存的不同部分。复制到的这个空白空间不是堆的一部分,至少,就 Xmx 参数而言不是。它就像“新堆”一样,在复制后成为堆的一部分(旧空间用于下一次 GC)。如果你有一个 512MB 的堆,它是 510MB,Java 将把实时数据复制到某个地方。天真的想法是另一个大型开放空间(如 500+MB)。如果您的所有数据都是“实时”的,那么它需要像这样的大块来复制。
因此,您可以看到,在最极端的情况下,您至少需要将系统上的可用内存增加一倍才能处理特定的堆大小。512MB 堆至少需要 1GB。
事实证明,实际情况并非如此,内存分配等比这更复杂,但您确实需要大量空闲内存来处理堆副本,这会影响整体进程大小。
最后,请注意 JVM 会做一些有趣的事情,例如将 rt.jar 类映射到 VM 以简化启动。它们映射在只读块中,并且可以在其他 Java 进程之间共享。这些共享页面将对所有 Java 进程“计数”,即使它实际上只消耗物理内存一次(虚拟内存的魔力)。
现在至于为什么您的进程继续增长,如果您从未遇到 Java OOM 消息,则意味着您的泄漏不在 Java 堆中,但这并不意味着它可能不在其他地方(JRE 运行时,第 3 方 JNI 库、本机 JDBC 驱动程序等)。