Java 加载100MB文件时发生OutOfMemoryError,尽管堆大小为550MB

Java 加载100MB文件时发生OutOfMemoryError,尽管堆大小为550MB,java,memory,heap,out-of-memory,heap-memory,Java,Memory,Heap,Out Of Memory,Heap Memory,以下问题: 我启动我开发的程序(-Xmx550M) 我加载了一个90MB的文件 此加载是下图中所用堆的峰值。在此之后,堆大小从130 MB增加到500 MB,尽管只需要110 MB 好吧,没问题,很烦人,但还好。但是,如果我现在启动一个保存进程(需要大约100 MB),Java VM将崩溃,并出现Java.lang.OutOfMemoryError:Java堆空间异常 如果我以750MB堆大小启动应用程序,它就可以正常工作。您可以看到短峰,它工作正常: 现在我的问题是:为什么我会得到一个55

以下问题:

  • 我启动我开发的程序(-Xmx550M)
  • 我加载了一个90MB的文件
  • 此加载是下图中所用堆的峰值。在此之后,堆大小从130 MB增加到500 MB,尽管只需要110 MB

    好吧,没问题,很烦人,但还好。但是,如果我现在启动一个保存进程(需要大约100 MB),Java VM将崩溃,并出现Java.lang.OutOfMemoryError:Java堆空间异常

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

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

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


    请帮帮我!

    如果加载100Mb的文件,这并不意味着内存中用于此文件的结构占用100M。例如,如果有字符串,则其长度也会有4字节的开销。

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


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

    附带问题:你是如何获得这些漂亮的图片的?@Thatidotguy我正在使用Netbeans Profiler;)啊,现在我必须找出Eclipse是否为我提供了这样的功能。你是如何加载文件的?如果不是以字节形式加载,而是以字符串形式加载,则编码和解码开销(以及UTF-16字符的开销)可能会导致这种峰值。@Ph3n1x我仍然认为您应该运行某种复杂的内存/GC分析器,如果程序在750MB的堆中运行正常,但在550MB的堆中运行不正常,则意味着它需要550MB以上的内存,而400MB的计算方式是有缺陷的。您不能使用图表来确定最大值,因为这只显示了在失败前一小段时间内使用了多少。@Peter Lawrey下面的图表显示了750 MB的运行情况,运行正常。我重复了几次,每次保存时使用的堆总是~400 MB。我的结论是:应用程序最多需要400 MB。但是550 MB的堆崩溃了…我以字节的形式加载它,没有字符串您是否使用任何其他影响生成大小的命令行选项?例如,如果您有最小或最大新闻大小,您可能会发现无法使用一个大型阵列的所有内存,因为即使您总共有足够的内存,它也无法装入eden或旧的gen空间。下图显示了750 MB的运行情况,在这一情况下运行良好。我重复了几次,每次保存时使用的堆总是~400 MB。我的结论是:应用程序最多需要400 MB。但是550MB的堆会崩溃…@Ph3n1x我认为关键是,即使是一个非常短暂的阶段,需要超过550MB的内存,也会导致失败。除非使用高内存使用来维持采样间隔的很大一部分,否则一个采样报告将不可能看到它。您还必须考虑到您的内存分为四个区域,一个EDEN,两个幸存者和一个老世代。如果您尝试分配一个大型对象,您会发现JVM无法调整您的各个区域大小,因此大型对象将适合其中任何一个区域。如果您使用其他与GC相关的选项,这意味着JVM不能自由地更改大小,那么这种情况就更可能发生。