内存不足—java进程中的outofmemoryexception,但使用的堆大约是使用大小的一半

s3fp2yjn  于 2021-07-12  发布在  Java
关注(0)|答案(2)|浏览(437)

我们正在运行一个进程,它有一个消耗大量内存的缓存。但是缓存中的对象数量在执行过程中保持稳定,而内存使用量却在无限增长。
我们已经运行java飞行记录器来尝试猜测发生了什么。
在那个报告中,我们可以看到usedheap大约是usedsize的一半,对此我找不到任何解释。
jvm退出并转储outofmemory报告,您可以在这里找到:https://frojasg1.com/stackoverflow/20210423.outofmemory/hs_err_pid26210.log
下面是整个java飞行记录器报告:https://frojasg1.com/stackoverflow/20210423.outofmemory/test.7z

有人知道为什么会有这样的回忆吗?
也许我得换个问题。。。并问:为什么堆中几乎有10gb的已用内存没有使用?

50few1ms

50few1ms1#

日志文件显示:


# Native memory allocation (mmap) failed to map 520093696 bytes

for committing reserved memory.

因此,jvm已经通过一个 mmap 系统调用,操作系统拒绝了。
当我查看更多的日志文件时,很明显g1gc本身正在请求更多的内存,看起来它正在尝试扩展heap1。
我可以想出几个可能的原因 mmap 失败:
操作系统可能没有交换空间来支持内存分配。
jvm可能已达到每个进程的内存限制(在unix/linux上,这是作为ulimit实现的。)
如果您的jvm运行在docker(或类似的)容器中,那么您可能已经超出了容器的内存限制。
这不是一个“正常”的oome。这实际上是jvm的内存需求与操作系统提供的内存之间的不匹配。
它可以在操作系统级别解决;i、 e.通过移除或增加限制,或添加更多交换空间(或可能更多ram)。
也可以通过减少jvm的最大堆大小来解决这个问题。这将阻止gc尝试将堆扩展到不可持续的大小2。这样做也可能导致gc更频繁地运行,但这比应用程序过早地死于可避免的oome要好。
1-在g1gc诊断方面有更多经验的人可能能够从崩溃转储中分辨出更多信息,但在我看来这是正常的堆扩展行为。没有明显的迹象表明有一个“巨大”的物体被创造出来。
2-确定可持续的大小实际上包括分析整个系统的内存使用情况,查看可用的ram和交换资源以及限制。这是一个系统管理问题,而不是编程问题。

euoag5mw

euoag5mw2#

也许我得换个问题。。。并问:为什么堆中几乎有10gb的已用内存没有使用?
您看到的是当前分配给堆的内存与设置的堆限制之间的差异。jvm实际上并不预先从操作系统请求所有堆内存。相反,它要求更多的内存增量。。。如果需要。。。在主要gc运行结束时。
因此,虽然堆的总大小看起来约为24gb,但实际分配的内存却远远小于这个值。
正常情况下,这很好。gc向os请求更多内存,并将其添加到相关池中,供内存分配器使用。但在这种情况下,操作系统无法满足要求,g1gc拔掉了插头。

相关问题