【问题标题】:Java memory usage on LinuxLinux 上的 Java 内存使用情况
【发布时间】:2011-04-08 11:17:51
【问题描述】:

我正在运行一些 Java 应用程序服务器,它们都在 CentOS 5.5 Linux 之上运行最新版本的 Tomcat 6 和 Sun 的 Java 6。每台服务器运行多个 Tomcat 实例。

我正在设置 -Xmx450m -XX:MaxPermSize=192m 参数来控制堆和 permgen 的增长量。这些设置适用于所有 Java 应用程序服务器上的所有 Tomcat 实例,总共大约 70 个 Tomcat 实例。

这是 Psi-probe 报告的其中一个 Tomcat 实例的典型内存使用情况

Eden           = 13M
Survivor       = 1.5M 
Perm Gen       = 122M 
Code Cache     = 19M 
Old Gen        = 390M 
Total          = 537M

然而,CentOS 报告此特定进程的 RAM 使用量为 707M(根据 RSS),这使得 170M 的 RAM 下落不明。

我知道 JVM 本身和它的一些依赖库必须加载到内存中,所以我决定启动 pmap -d 来找出它们的内存占用。 根据我的计算大约占1700万。

接下来是 Java 线程堆栈,在 Linux 的 32 位 JVM 上每个线程有 320k。 同样,我使用 Psi-probe 来计算特定 JVM 上的线程数,总数为 129 个线程。所以 129 + 320k = 42M

我听说 NIO 使用堆外的内存,但我们不在应用程序中使用 NIO。

所以我在这里计算了(我)想到的所有内容。而我只占了“缺失”的 170M 中的 60M。

我错过了什么?

【问题讨论】:

  • 我自己也一直在问同样的问题。我发现我们有一堆匿名页面(由 pmap 返回),大小从 65536k 到 65508k 不等。不确定这些是什么,但它们占我们内存使用量的三分之一左右。

标签: java linux memory


【解决方案1】:

尝试使用增量垃圾收集器,使用 -Xincgc 命令行选项。 它在整个 GC 工作上更具侵略性,并且有一个特别令人高兴的小异常:它实际上将一些未使用的内存交还给操作系统,这与默认和其他 GC 选择不同! 这使得 JVM 消耗更少的内存,如果您在一台机器上运行多个 JVM,这尤其有用。以牺牲一些性能为代价——但你可能没有注意到它。 incgc 似乎是个小秘密,因为从来没有人提起过它……它已经存在了好久(甚至是 90 年代)。

【讨论】:

    【解决方案2】:

    Arnar,在 JVM 初始化过程中,JVM 将分配一个大小由 -Xmx 和 MaxPermSize 指定的内存(mmap 或 malloc),因此无论如何 JVM 将在 JVM 进程开始时为应用程序分配 450+192=642m 的堆空间.所以应用程序的java堆空间不是537而是642m。所以现在如果你进行计算,它会给你丢失的内存。希望它有所帮助。

    【讨论】:

    • 我认为您可以使用 Xms 开关设置初始堆,它只会根据需要增长到 Xmx 大小。
    • 是的,最初应用程序将被赋予等于-Xms的大小来分配对象,并根据应用程序的要求进一步增长到-Xmx。但是JVM堆是一个大小连续的空间-Xms + Perm 大小。当堆增长时,将从这个大小为 -Xmx 的预分配空间中获得更多内存。
    • -Xms 是一个帮助JVM决定何时触发GC的参数,所以每当应用程序完全占用大小为-Xms的堆时,JVM就会触发GC并尝试清理垃圾对象,之后如果 GC 没有清理太多空间来分配应用程序对象请求,那么 JVM 将扩展一定量的堆。(收缩和扩展也是基于太多其他因素)。
    • 感谢您回复阿尼尔。我刚刚重新启动了有问题的 JVM,一旦它完全初始化,RSS 内存占用量仅为 273M。 JVM heap + permgen + code cache + native code size + thread stack 目前是248M。所以我不认为整个堆都被分配给 RSS 内存。如果我没有指定 -Xms 或 -XX:PermSize,JVM 会将 -xms 设置为 64mb(可用 RAM 的 1/64,即 4G),并将 XX:PermSize 设置为 64mb。
    • -Xmx 是预先分配的,因为 JVM 需要一块连续的地址空间。但这并不意味着将使用所有这些内存。在 Linux 系统上,它将被标记为非活动的并且不会常驻。这就是为什么您的 RSS(驻留集大小)可以更低的原因。
    【解决方案3】:

    Java 会预先分配尽可能多的虚拟内存,但驻留端将取决于您实际使用的内存量。注意:许多库和线程都有自己的开销,虽然您不使用直接内存,但这并不意味着底层系统都不使用。例如如果你使用 NIO,即使你使用 heap ByteBuffers,它也会使用一些直接内存。

    最后,100 MB 的价值约为 8 英镑。可能不值得花太多时间担心它。

    【讨论】:

    • Peter,我在许多应用服务器上运行了大约 70 个 Tomcat 实例。这个数字真的加起来了。
    • 那么您如何部署新应用程序并独立回滚/删除它们。您有效地将根/系统拥有的平面文件用作数据库,而不支持事务或独立操作。恕我直言,您拥有的服务越多,您的解决方案对我来说就越糟糕。如果您有多个盒子,那么一个系统无法正确部署的可能性对您来说一定是个问题。
    【解决方案4】:

    不是直接回答,但是,您是否也考虑过托管multiple sites within the same Tomcat instance?这可以节省一些内存,但需要进行一些额外的配置。

    【讨论】:

      【解决方案5】:

      Arnar,JVM 还使用了 mmap 的所有 jar 文件,这些文件将使用 NIO 并有助于 RSS。我不相信你在上面的任何测量中都考虑了这些。您是否碰巧拥有大量大型 jar 文件?如果是这样,用于这些的页面可能是您丢失的内存。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2010-10-08
        • 2010-12-25
        • 2015-02-07
        • 1970-01-01
        • 2011-01-30
        • 2018-01-16
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多