【问题标题】:How to ensure JVM starts with value of Xms如何确保 JVM 以 Xms 的值启动
【发布时间】:2010-10-26 02:51:45
【问题描述】:

当我运行一个起始堆大小为 3G(由 -Xms3072m VM 参数设置)的 java 程序时,JVM 不会以该大小开始。它从 400m 左右开始,然后根据需要不断获取更多内存。

这对我来说是一个严重的问题。我知道 JVM 会在一段时间后需要上述数量。当JVM根据需要增加它的内存时,它就会变慢。在 JVM 获取更多内存期间,大量时间用于垃圾收集。而且我认为内存获取是一项昂贵的任务。

我如何确保 JVM 确实尊重起始堆大小参数?

更新:这个应用程序创建了很多对象,其中大部分很快就死掉了。一些生成的对象需要留在内存中(这些对象从年轻堆中转移出来)。在此操作期间,所有这些对象都需要在内存中。运行后,可以看到young heap中的所有对象都被认领成功了。所以没有内存泄漏。

当堆大小达到 3G 时,同样的操作可以顺利运行。这清楚地表明需要花费额外的时间来获取内存。

这个 Sun JDK 5。

【问题讨论】:

  • 你在使用 Sun 的 JVM 吗?
  • 只是一个问题:你的机器有多少主存,启动程序时有多少空闲?
  • 主机有32G内存。虽然,“top”只显示了几 Gig 的可用内存,但 java 程序可以轻松地分配 10G。
  • 我的想法是,您即将进行交换,当 Java 分配另一个内存区域时,操作系统必须负责交换和压缩。

标签: java garbage-collection jvm heap-memory


【解决方案1】:

如果我没记错的话,Java 会尝试从操作系统获取内存预留。因此,如果您要求 3 GB 作为 Xms,Java 将询问操作系统,如果这可用但不是立即从所有内存开始......它甚至可能保留它(而不是分配它)。但这些都是细节。

通常,JVM 在开始严重的老年代垃圾收集之前会运行到 Xms 大小。年轻代 GC 一直在运行。通常 GC 仅在老一代 GC 正在运行且 VM 介于 Xms 和 Xmx 之间时才明显,或者,如果您将其设置为相同的值,则大致达到 Xmx。

如果您需要大量内存来存储短期对象,请通过将年轻区域设置为...来增加该内存区域...比如说 1 GB -XX:NewSize=1g,因为这样做的成本很高将“垃圾”从年轻的“桶”移到老一代。因为如果它还没有变成真正的垃圾,JVM 会检查垃圾,没有找到任何垃圾,在幸存者空间之间复制它,最后移动到老一代。因此,当您知道自己没有任何垃圾并以某种方式推迟时,请尝试抑制对年轻一代的垃圾检查...

试一试!

【讨论】:

    【解决方案2】:

    我相信您的问题并非出自您的想法。

    看起来最耗费您的是 GC 周期,而不是堆大小的分配。如果您确实在创建和删除大量对象。

    您应该将精力集中在分析上,找出究竟是什么让您付出了如此多的代价,并努力重构它。

    我的预感——对象创建和删除,以及 GC 循环。

    无论如何,-Xms 应该设置最小堆大小(用你的 JVM 检查这个,如果它不是 Sun)。仔细检查以了解您认为不是这种情况的确切原因。

    【讨论】:

      【解决方案3】:

      我使用了 sun 的 vm 并从最低设置为 14 gigs 开始,它确实从那开始。 也许你应该尝试将 xms 和 xmx 值设置为相同的 amt,即试试这个- -Xms3072m -Xmx3072m

      【讨论】:

        【解决方案4】:

        为什么你认为堆分配不对?拿任何只显示 400m 的操作系统工具并不意味着它没有被分配。

        我真的不明白你在追求什么。 400m 及以上是否已经成为问题,或者您的程序应该需要那么多?如果您确实需要处理这么多的内存,并且您似乎需要很多对象,那么您可以做几件事:

        如果内存消耗与您的直觉不符,那么您的内存消耗量可能是正确的。这可以解释为什么它会随着时间的推移而“减速”。也许您错过了从一个结构中删除对象,这样它们就不会被垃圾收集,并且会减慢查找速度等。

        您的内存设置本身可能就是问题所在。垃圾收集本身不运行。只有在达到某个阈值时才会调用它。如果你给它一个大的堆设置并且你的操作系统有足够的内存,那么垃圾收集就不会经常运行。

        您提到的特征是创建大量对象并在不久之后再次删除它们的场景。否则垃圾收集不会成为问题(某种分代 gc)。这意味着你只有“年轻”的对象。如果您仅在短时间内需要对象,请考虑使用对象池。这将完全消除垃圾收集。

        如果您知道代码中有运行 gc 的好时机,您可以考虑手动运行它以查看它是否有任何变化。这就是你需要的

          Runtime r = Runtime.getRuntime();
          r.gc();
        

        这仅用于调试目的。 gc 在大多数情况下都做得很好,因此不需要您自己调用 gc。

        【讨论】:

          猜你喜欢
          • 2013-01-23
          • 2019-11-01
          • 1970-01-01
          • 1970-01-01
          • 2012-08-01
          • 2010-10-23
          相关资源
          最近更新 更多