【问题标题】:Java Runtime.maxMemory incorrect?Java Runtime.maxMemory 不对?
【发布时间】:2010-11-30 15:15:35
【问题描述】:

我运行了以下方法 Runtime.getRuntime().maxMemory() 并给了 85196800.

但是,我随后从命令行运行 top 并显示了

  PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND                                                                                                       
 8672 root      20   0 1284m 156m 4296 S  0.3 60.9   0:33.35 java        

这不是显示使用了 156M 的内存吗?有什么想法吗?

【问题讨论】:

    标签: java performance optimization memory memory-leaks


    【解决方案1】:

    如果您想了解为什么 top 显示的内存消耗比 jvm 中设置的多。

    这是我过去的经历

    我们已经看到 TOP 和其他类似实用程序显示消耗的内存比我们最初在 JVM 参数中设置的要多。

    在我们的例子中,环境是: AIX/Websphere 应用服务器。

    原因是: 我们在应用程序中使用的 Classpath 中定义了一个共享库。 这个特定的库 (PureedgeAPI)实际上跨越了另一个进程或进行了 JNI 调用。 (为了清楚起见,很少有 .SO 库) 在我们几次不正确的调用之后——我的意思是不通过调用这个 objects.destroy() 而不仅仅是将其设置为 NULL。我们已经看到内存在 2GB(最大设置)的 jvm 上提升到 30GB 的水平

    从操作系统的角度来看:因为 JAVA 是原始进程 - 此 JNI 调用的所有子实例也被记录为使用它的同一个 JAVA 父进程。

    我没有方便的命令 - 但我实际上会看到这个特定进程的树(这可能产生了另一个进程(在你的情况下是 java )。

    谢谢,

    【讨论】:

      【解决方案2】:

      该方法的 Javadocs 是错误的,或者至少非常具有误导性。这个Sun bug report 解释了。

      另外一点是显示为RES的156Mb是当前的“驻留集”大小;即当前归属于应用程序的物理 RAM 量。这个数字可能会根据系统服务/守护程序和机器上运行的应用程序的虚拟内存需求而增加和减少。 JVM 声称报告的数字是 JVM 的虚拟内存分配。

      只要说这一切都像泥巴一样清晰,可能不值得你努力去弄清楚。如果你真的很在意,请注意topvmstat 等告诉你的内容,而忽略 JVM 编号。

      【讨论】:

        【解决方案3】:

        Runtime.getRuntime().maxMemory() 返回的是最大堆大小的估计值,而不是整个进程将消耗的内存总量。本机内存、本机库等会影响进程大小,但不会影响 maxMemory()。

        【讨论】:

          【解决方案4】:

          从文档中,

          maxMemory() - 返回 Java 虚拟机将尝试使用的最大内存量。

          Top 仅显示系统分配给进程的(虚拟)内存量 - 您是在询问 Java 在最坏的情况下它可以尝试使用多少。

          一般来说,查询 JVM 和/或系统以获取有关实际使用内存的信息是不可靠的。例如,top 的数字可能包括已分配但未使用或分页的内存。它还可以包括共享库之类的东西,其中一个 10MB 的库可能会计算两个进程的分配,但内存中只有一个物理副本。 (例如)

          你想做什么?

          【讨论】:

          • VIRT 显示的不就是这样吗?我认为 RES 显示了实际使用的内存,这超出了 JVM 将尝试使用的内存,没有意义
          • 这里的问题是 maxMemory 应该返回一个我可以期望 jvm 不会超过的数字。但它确实如此,我的 java 进程的 RES 编号不断增长,并使我的服务器停止运行!为什么不遵循 maxMemory 规则?
          • 您将哪些命令行选项传递给您的服务器?具体来说,-Xmx 和 -Xms。 Top 可能报告了函数调用没有的一些事情——我猜想顶部的 RES 字段确实包含共享库,但 JVM 并不将其计入它自己的使用中。堆栈空间也可能属于该类别......您可能不应该依赖于询问 Runtime 类它将使用多少内存。我会改为调整 -Xmx 和 -Xms,并有足够的交换空间来处理任何临时超额。
          • 我用的是默认设置,也就是说堆不应该超过83Mb,我是如何在VIRT中得到1284Mb的??
          • VIRT 并没有真正反映太多。我刚刚写了一个 malloc() 占用大量内存但从未使用过它的程序,这会导致一个荒谬的 VIRT 测量结果,但几乎没有使用任何实际内存。
          猜你喜欢
          • 2022-09-23
          • 2014-07-05
          • 2012-01-21
          • 2012-07-16
          • 2015-10-02
          • 2016-10-24
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多