Java进程中的OutOfMemoryException,但使用的堆大约是使用大小的一半

Java进程中的OutOfMemoryException,但使用的堆大约是使用大小的一半,java,out-of-memory,Java,Out Of Memory,我们正在运行一个进程,该进程有一个消耗大量内存的缓存。 但缓存中的对象数量在执行过程中保持稳定,而内存使用量却在无限增长 我们运行Java Flight Recorder是为了猜测发生了什么 在该报告中,我们可以看到UsedHeap大约是UsedSize的一半,对此我找不到任何解释 JVM退出并转储一个OutOfMemory报告,您可以在这里找到: 下面是整个Java飞行记录器报告: 有人知道为什么会产生这种记忆的后果吗 也许我不得不改变这个问题。。。并询问:为什么堆中没有使用近10GB的

我们正在运行一个进程,该进程有一个消耗大量内存的缓存。 但缓存中的对象数量在执行过程中保持稳定,而内存使用量却在无限增长

我们运行Java Flight Recorder是为了猜测发生了什么

在该报告中,我们可以看到UsedHeap大约是UsedSize的一半,对此我找不到任何解释

JVM退出并转储一个OutOfMemory报告,您可以在这里找到:

下面是整个Java飞行记录器报告:

有人知道为什么会产生这种记忆的后果吗


也许我不得不改变这个问题。。。并询问:为什么堆中没有使用近10GB的已用内存?

日志文件说:

因此,发生的情况是JVM通过
mmap
系统调用从操作系统请求了大约500MB的内存块,而操作系统拒绝了

当我查看更多的日志文件时,很明显G1GC本身正在请求更多的内存,看起来它在尝试扩展heap1时正在这样做

我可以想到导致
mmap
失败的几个可能原因:

  • 操作系统可能缺少支持内存分配的交换空间

  • JVM可能已达到每进程内存限制。(在UNIX/Linux上,这是作为ulimit实现的。)

  • 如果JVM在Docker(或类似)容器中运行,则可能已超出容器的内存限制


  • 这不是一个“正常”的OOME。这实际上是JVM的内存需求与操作系统的可用内存之间的不匹配

    • 它可以在操作系统级别解决;i、 e.通过移除或增加限制,或添加更多交换空间(或可能更多RAM)

    • 还可以通过减少JVM的最大堆大小来解决这个问题。这将阻止GC尝试将堆扩展到不可持续的大小2。这样做也可能会导致GC更频繁地运行,但这比应用程序因可避免的OOME过早死亡要好


    1-在G1GC诊断方面有更多经验的人可能能够从崩溃转储中辨别出更多信息,但在我看来这是正常的堆扩展行为。没有明显的“巨大”物体被创建的迹象。
    2-确定可持续的大小实际上需要分析整个系统的内存使用情况,并查看可用RAM和交换资源以及限制。这是一个系统管理问题,而不是编程问题


    也许我不得不改变这个问题。。。并问:为什么堆中没有使用近10GB的已用内存

    您看到的是当前分配给堆的内存与您设置的堆限制之间的差异。JVM实际上并不预先从操作系统请求所有堆内存。相反,它以增量方式请求更多内存。。。如果需要。。。在主要GC运行结束时

    因此,尽管堆的总大小看起来约为24GB,但实际分配的内存却大大小于此值


    通常情况下,这很好。GC向操作系统请求更多内存,并将其添加到相关池中,供内存分配器使用。但在这种情况下,操作系统无法满足要求,G1GC拔掉了插头。

    感谢您的快速回答。系统有24 GB内存,进程占用的内存超过22 GB,因此OutOfMemory错误可能是因为系统内存不足。我们已经执行了“top-o%MEM”命令,通过该命令,我们可以看到进程几乎使用了系统的所有内存。我不是这方面的专家,但总的内存使用量大约是堆使用量的两倍,这听起来很奇怪。。。可能是因为对术语的任何误解,但,若堆中并没有使用内存,还有什么地方?也许回答这个问题是关键。也许我必须改变这个问题。。。并问:为什么堆中没有使用近10GB的已用内存?我必须纠正我的最新评论:降低java应用程序的内存:-[系统的总RAM:24GB]-[以前的Xmx:-Xmx24000m(提供outOfMemory)。]-[将java应用程序的内存限制在:-Xmx20000m,似乎已经解决了问题。]非常感谢Stephen C,您的答案似乎是好的+1是。我对间接原因的看法是错误的。我已更新了我的答案。
    # Native memory allocation (mmap) failed to map 520093696 bytes 
    for committing reserved memory.