3

在编写一个必须分配许多对象的应用程序时,我收到了一个异常java.lang.OutOfMemoryError: Java heap space。在阅读How to deal with “java.lang.OutOfMemoryError: Java heap space” error (64MB heap size)java.lang.OutOfMemoryError: Java heap space我尝试运行java -jar myJar.jar -Xms1024m -Xmx4096m命令时,但应用程序在分配约 1.457 GB 时崩溃. 这是在 64 位 Win XP 框中。使用或不使用 -Xmx 时,崩溃时刻在 java.exe 进程的内存使用方面保持不变。64 位应用程序不应该能够在 64 位操作系统中使用 4 GB 的 RAM 吗?

4

2 回答 2

3

这是一个非常复杂的话题。没有简单的解决方案,一两个参数可以避免OOM。尽管如此,我们可以应用一些非常有用的概念和技术来解决问题。

事实上,您可以使用来自 OOM 的转储文件执行初始分析,方法是使用 -XX:-HeapDumpOnOutOfMemoryError 之类的参数。你的分析应该集中在哪个部分被用完。是堆还是烫发?以及堆中的对象是如何分布的,例如发生 OOM 时最大对象/类的大小是多少。像MAT这样的工具是一个很好的工具。

  1. OOM 可能发生在堆中。

    将堆大小增加 -Xmx。(看来这不适用于您的情况)。但是我建议您也将 -Xms 设置为 4G,以查看您是否有足够的内存并可以为您的 JVM 进程保留。如果您仍然可以遇到 OOM,则可能是碎片问题。这意味着,在分配和释放内存块的情况下运行相当长的时间后,您的堆是碎片化的,并且没有大的连续空间可用于大对象的分配请求。例如,如果堆中最大的连续空闲空间是 200M——尽管堆中的总空闲空间是 2G——并且如果您的应用程序请求一个大对象,比如一个大小为 250M 的数组,那么您就会遇到 OOM。启用 gc 日志并使用 GC 日志分析器可以为您提供这方面的信息。另请参阅此博客以更好地理解和建议如何避免碎片化。

  2. OOM可能发生在烫发区。

    将烫发大小增加 -XX:MaxPermSize=384m。Perm 意味着用于类元数据和静态变量的区域。如果您的应用程序(或您的程序使用的库)加载大量类,或动态加载许多类,您可能需要更大的 perm 大小。如果增加大小不起作用,您可能会在类加载中出现泄漏。然后应使用 MAT 或内存泄漏检测器进行调查。

最后,不同的 JVM 品牌和版本在内存结构和参数方面存在差异。例如,“在 JDK 7 中,interned 字符串不再分配在 Java 堆的永久代中,而是与其他对象一起分配在 Java 堆的主要部分(称为年轻代和年老代)中由应用程序创建。” 因此,请务必检查您正在使用的 JDK 版本的文档。

于 2013-11-11T02:21:56.750 回答
1

您可以使用 64 位 JVM 在 64 位窗口上分配 64 GB 堆。(或者更大,但我没试过)

如果您收到 OutOfMemoryError,则意味着您也无法分配更多对象,因为

  • 你使用的比你想象的要多,或者
  • 您的内存非常碎片化,例如 CMS 不会对永久空间进行碎片整理。

例如,假设您提供了不超过 4 KB 的连续内存,并且您正在使用不会对内存进行碎片整理的 CMS,并且您增长了像 ArrayList 或 StringBuidler 或 HashMap 这样的集合,它无法分配对象并因此引发 OutOfMemoryError。

于 2013-11-11T03:07:24.523 回答