【问题标题】:Java using up far more memory than allocated with -XmxJava 使用的内存远多于使用 -Xmx 分配的内存
【发布时间】:2013-02-23 07:11:56
【问题描述】:

我正在编写一个项目(用 Java 编写),教授说我们不允许使用超过 200m 的类 我使用 -Xmx50m 将堆栈内存限制为 50m(绝对确定),但根据顶部,它仍在使用 300m

我尝试运行Eclipse Memory Analyzer,它只报告了 26m

这可能都是堆栈上的内存吗?我很确定我永远不会超过大约 300 个方法调用深度(是的,这是一个递归 DFS 搜索),所以这意味着每个堆栈帧都在使用几乎是一兆字节,这似乎令人难以置信。

程序是单线程的。有谁知道我可能会减少内存使用的其他地方?另外,如何检查/限制堆栈使用的内存量?

更新:我现在正在使用以下 JVM 选项,但没有任何效果(根据顶部仍然大约 300m):-Xss104k -Xms40m -Xmx40m -XX:MaxPermSize=1k

另一个更新:实际上,如果我让它运行更长一点(使用所有这些选项)大约一半的时间它会在 4 或 5 秒后突然下降到 150m(另一半不会下降)。真正奇怪的是我的程序没有随机性(正如我所说它是单线程的),所以没有理由在不同的运行中表现不同

会不会和我使用的 JVM 有关?

java version "1.6.0_27"
OpenJDK Runtime Environment (IcedTea6 1.12.3) (6b27-1.12.3-0ubuntu1~10.04)
OpenJDK 64-Bit Server VM (build 20.0-b12, mixed mode)

根据java -h,默认JVM是-server。我尝试添加 -cacao,现在(使用所有其他选项)它只有 59m。所以我想这可以解决我的问题。谁能解释为什么这是必要的?另外,有什么我应该知道的缺点吗?

另一个更新:cacao 与服务器相比真的很慢。这是一个糟糕的选择

【问题讨论】:

  • 堆内存和栈内存是分开配置的。您在顶部看到的内存包括两者。
  • 我意识到这一点,但我不认为这是堆栈内存。我没用那么多。那么内存还可能来自哪里
  • 您是否也设置了最小堆大小?如果-Xms大于-Xmx,我认为它最多使用-Xms
  • 我正在使用-server,我认为它设置了最小堆大小,但没有明确
  • 也尝试将其设置为 50m。

标签: java memory memory-management stack


【解决方案1】:
Max memory = [-Xmx] + [-XX:MaxPermSize] + number_of_threads * [-Xss]

这里最大堆内存为-Xmx,最小堆内存为-Xms,堆栈内存为-Xss 和 -XX maxPermSize

以下示例说明了这种情况。我已经使用以下启动参数启动了我的 tomcat:

-Xmx168m -Xms168m -XX:PermSize=32m -XX:MaxPermSize=32m -Xss1m

【讨论】:

    【解决方案2】:

    请务必注意,“使用的总内存”(Linux 领域中的 RSS)包括 JDK 堆(+ 其他 JDK 区域)以及分配的任何“本机内存”。

    例如,这些人发现在 GC 之间分配过多的 jaxbcontexts(具有关联的本机内存)可能会导致它使用大量额外的 RAM。另一个常见的显然是 ZipInflater,如果你不调用它(或 GZipStream 等)

    http://sleeplessinslc.blogspot.com/2014/08/jvm-native-memory-leak.html

    他的最终解决方法/修复是“更频繁地”进行 GC(通过使用 GC1 垃圾收集器,或指定 更小 [讽刺地] -Xmx 设置)或缓存 JaxBContext 对象(因为它们没有关闭方法,所以无法控制泄漏)。

    另请注意,有时您可以通过检查 jstack 找到内存罪魁祸首:http://javaeesupportpatterns.blogspot.com/2011/09/jaxbcontext-performance-problem-case.html

    有时也可能“错过”关闭,例如 GZipStreams 意外http://kohsuke.org/2011/11/03/quiz-time-memory-leak-in-java

    【讨论】:

      【解决方案3】:

      使用-Xmx,您正在配置堆大小。要配置堆栈大小,请使用 -Xss 参数。这两个参数的总和应该大约是您想要的:

      -Xmx150m -Xss50m
      

      例如。

      另外还有-XX:MaxPermSize参数控制。 -client 的此参数的默认值为 32mb,-server 的默认值为 64mb。根据您的配置计算它也是如此。 PermGen 空间是:

      永久代用于保存 VM 本身的反射,例如类对象和方法对象。

      所以基本上它存储了 JVM 的内部数据,比如类定义和实习字符串。

      最后我必须说,有一个部分是你无法控制的,那就是本地 java 进程使用的内存。 Java 是程序,就像其他程序一样,所以它也使用内存。如果您在任务管理器中查看内存使用情况,您将看到此内存以及您的程序内存消耗。

      【讨论】:

      • 别忘了 PermGen 空间
      • 谢谢,我刚刚找到并尝试过。它没有任何区别。我没有用完堆栈内存。如果不是堆或堆栈,它还能从哪里来
      • 什么是 PermGen 空间以及如何限制它?
      • 加载的类去那里,我想可能是一些静态的。您可以使用 -XX:MaxPermSize=128M 进行设置
      • 是的,但我之前运行的java程序很容易使用不到300m。本机 java 进程使用的内存只是不断的开销,不是吗?
      【解决方案4】:

      您是否尝试过使用 JVisualVM?

      http://docs.oracle.com/javase/6/docs/technotes/tools/share/jvisualvm.html

      我经常发现它可以帮助我追踪这些东西。它会向您显示每种内存的使用量,甚至让您深入了解哪些内容。

      【讨论】:

      • 好像没有适用于linux的版本
      • 应该在JDK(不是JRE)的bin目录下;这可能不在您的 PATH 上。
      【解决方案5】:

      Top 命令反映了 Java 应用程序使用的内存总量。其中包括:

      • JVM 本身的基本内存开销
      • 堆空间(以 -Xmx 为界)
      • 永久代空间(-XX:MaxPermSize - 并非所有 JVM 的标准)
      • 线程堆栈空间(每个堆栈 -Xss)可能会显着增长,具体取决于线程数
      • 本机分配使用的空间(使用 ByteBufer 类或 JNI)

      【讨论】:

      • 没有字节缓冲区(除非集合框架中的某些东西使用它们),限制 PermGen 似乎并没有改变任何东西。我确实调用了我认为使用 JNI 的 System.arraycopy,对吗?会这样吗?
      • @dspyz:我不认为 arrayCopy 使用堆空间之外的额外空间。它将数据从一个堆位置复制到另一个。我会重新检查您的应用程序产生的线程数。
      • 不,单线程。我所看到的(在 Eclipse 调试器中)是主线程、信号调度程序、终结器和引用处理程序
      • @dspyz:进程的共享内存呢?我认为您可以使用 jmap (jmap ) 检查它。当你启动多个 java 进程时,它们的总内存不是 top 显示的总和,因为它们使用共享库。
      • 它还包括共享库/dll的大小,可能还有操作系统用来缓存加载的类文件的空间等。
      猜你喜欢
      • 1970-01-01
      • 2011-11-02
      • 1970-01-01
      • 2014-01-11
      • 1970-01-01
      • 2015-12-03
      • 2013-11-14
      相关资源
      最近更新 更多