【问题标题】:What runs in a C heap vs a Java heap in HP-UX environment JVMs?在 HP-UX 环境 JVM 中,C 堆与 Java 堆中运行的是什么?
【发布时间】:2010-09-09 20:26:43
【问题描述】:

我在 HP-UX 环境中遇到了某些 Java 应用程序的特殊问题。

堆设置为 -mx512,但是,使用 gpm 查看此 java 进程的内存区域,它显示它使用了 1.6GB 的 RSS 内存,其中 1.1GB 分配给了 DATA 区域。在 24-48 小时内快速增长,然后大幅放缓,仍然每隔几个小时增长 2MB。但是,Java 堆没有泄漏的迹象。

很好奇这是怎么可能的,我进行了一些研究,发现了这篇关于 java 堆和 c 堆内存泄漏的 HP 文章:http://docs.hp.com/en/JAVAPERFTUNE/Memory-Management.pdf

我的问题是什么决定了在 C 堆和 java 堆中运行的内容,对于不通过 java 堆运行的东西,您将如何识别在 C 堆上运行的那些对象?此外,Java 堆是否位于 C 堆内?

【问题讨论】:

    标签: java c jvm heap-memory hp-ux


    【解决方案1】:

    考虑什么构成了 Java 进程。

    你有:

    • JVM(一个 C 程序)
    • JNI 数据
    • Java 字节码
    • Java 数据

    值得注意的是,它们都存在于 C 堆中(JVM 堆自然是 C 堆的一部分)。

    在Java 堆中只是Java 字节码和Java 数据。但是 Java 堆中还有“空闲空间”。

    典型的(即 Sun)JVM 只在必要时增加它的 Java Heap,但从不收缩它。一旦它达到其定义的最大值 (-Xmx512M),它就会停止增长并处理剩下的任何东西。当最大堆用尽时,您会收到 OutOfMemory 异常。

    Xmx512M 选项不做的是限制进程的整体大小。它只限制进程的 Java Heap 部分。

    例如,您可以设计一个使用 10MB 的 Java 堆的 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 驱动程序等)。

    【讨论】:

      【解决方案2】:

      一般来说,只有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 堆上的内存。

      【讨论】:

        【解决方案3】:

        我对您给出的数字的唯一猜测是 Java VM 中的内存泄漏。您可能想尝试他们在您提到的论文中列出的其他 VM 之一。另一种(更困难的)替代方法可能是在 HP 平台上编译 open java。

        Sun 的 Java 还没有 100% 开放,他们正在努力,但我相信 sourceforge 中有一个。

        顺便说一句,Java 也会破坏内存。有时它会稍微混淆操作系统内存管理(当 Windows 内存不足并要求 Java 释放一些内存时,你会看到它,Java 会触及它的所有对象,导致它们从交换文件中加载,Windows 痛苦地尖叫并死掉),但是我不认为这是你所看到的。

        【讨论】:

          猜你喜欢
          • 2010-10-11
          • 1970-01-01
          • 1970-01-01
          • 2013-07-06
          • 2012-12-31
          • 1970-01-01
          • 2012-04-08
          • 2011-02-13
          • 1970-01-01
          相关资源
          最近更新 更多