【问题标题】:OutOfMemoryError when loading 100MB file, despite 550MB heap尽管有 550MB 堆,但加载 100MB 文件时出现 OutOfMemoryError
【发布时间】:2012-12-01 21:57:27
【问题描述】:

以下问题:

  1. 我开始我开发的程序 (-Xmx550M)
  2. 我加载了一个 90 MB 的文件

这个加载是下图中已用堆的峰值。此后,堆大小从 130 MB 增加到 500 MB,尽管只需要 110 MB。

好吧,没问题,烦人,但没关系。但是,如果我现在启动一个保存过程(大约需要 100 MB),Java VM 会因 java.lang.OutOfMemoryError: Java heap space exception 而崩溃。

如果我以 750 MB 的堆大小启动应用程序,它可以正常工作。您会看到短暂的峰值,并且工作正常:

现在我的问题是:为什么我会得到一个 550 MB 堆大小的 OutOfMemoryError?该应用程序只需要 400 MB(在最高峰)!

我不知道如何解决这个问题:(

请帮帮我!

【问题讨论】:

  • 附带问题:你是怎么得到这些漂亮照片的?
  • @thatidiotguy 我正在使用 Netbeans Profiler ;)
  • 啊啊啊,现在我得看看 Eclipse 是否为我提供了这样的功能。
  • 你是如何加载文件的?如果您不是将其作为字节加载,而是作为String 加载,则编码和解码开销(以及 UTF-16 字符的开销)可能会导致这种峰值。
  • @Ph3n1x 我仍然认为您应该运行某种复杂的内存/GC 分析器,以获取更多信息并推动这件事。

标签: java memory out-of-memory heap-memory


【解决方案1】:

如果你加载 100Mb 的文件,这并不意味着用于该文件的结构在内存中占用 100M。例如,如果你有 String,那么它的长度也会有 4 个字节的开销。

【讨论】:

  • +1 如果程序在 750 MB 的堆上运行良好,但在 550 MB 的情况下运行良好,这意味着它需要超过 550 MB,并且计算 400 MB 要求的方式存在缺陷。您不能使用图表来确定最大值,因为这仅显示了在失败前一段时间使用了多少。
  • @Peter Lawrey 下图显示了运行良好的 750 MB。我重复了几次,保存时使用的堆总是~400 MB。我的结论:应用程序最多需要 400 MB。但是使用 550 MB 堆时它会崩溃...
  • 我将它作为字节加载,没有字符串
  • 您是否使用了任何其他影响世代大小的命令行选项?例如,如果你有一个最小或最大 newsize,你可能会发现你不能将所有内存用于一个大数组,因为它不适合 eden 或 old gen 空间,即使你总共有足够的内存。
【解决方案2】:

数据被采样。就在它失败之前它正在使用 400 MB,然后一段时间后它尝试使用更多内存,例如600 MB,但这没有显示,因为到下一个样本采集时,OOME 已经发生,您的使用率现在要低得多。

简而言之,您的程序使用内存的速度比您在图表中看到的要快。

【讨论】:

  • 下图显示了运行良好的 750 MB。我重复了几次,保存时使用的堆总是~400 MB。我的结论:应用程序最多需要 400 MB。但是使用 550 MB 堆时它会崩溃...
  • @Ph3n1x 我认为关键是即使是需要超过 550 MB 的非常非常短暂的阶段也会导致失败。除非高内存使用在采样间隔的很大一部分持续存在,否则采样报告不太可能看到它。
  • 您还必须考虑到您的记忆分为四个区域,一个伊甸园,两个幸存者和一个老一代。如果您尝试分配一个大对象,您会发现 JVM 无法调整各个区域的大小,因此大对象将适合其中的任何一个。如果您使用其他与 GC 相关的选项,则更有可能发生这种情况,这意味着 JVM 不能随意更改大小。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-03-21
  • 2014-08-13
  • 1970-01-01
  • 1970-01-01
  • 2017-09-20
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多