java堆内存管理内存不足

当一个netty异步服务器和客户端项目在linux上运行时,它会耗尽所有可用的内存,如下所示: linux控制台

所以我在Windows上运行它,JMC显示堆如下:

JMC记忆

我的问题是:为什么Windows和Linux的行为不同,有没有我可以配置linux jvm以释放堆内存? 为什么在Windows(GC)中有一个堆释放? 如何找出占用如此多内存的可疑代码?

编辑 :linux是4G,windows是8G,但我不认为绝对值会导致运行结果的差异。 Project不直接处理raw bytebuff,它使用HttpServerCodecHttpObjectAggregator进行bytebuf。 在linux中运行的命令是java -jar xx.jar 。 我不仅想知道为什么不同,为什么锯齿 ,还要知道如何找到占据如此多记忆的那个 。 JMC显示了另一个数字,我不知道为什么一个线程可以有这么高的块数。 netty线程IO有一个99行71ms。 JMC线程

更新:现在我想找到代码的哪一部分占用了这么多内存 。 JMC堆显示EDEN SPACE非常高,我发现它并发现EDEN SPACE是用于new对象的。 最初,该项目使用了spring-boot,它有tomcat servlet 3.0作为容器和apache httpclient池用于客户端,现在只使用netty异步服务器和netty异步客户端改变了这些部分,而其他部分仍然存在(仍然使用spring for豆管理)。 所有请求共享Netty服务器和客户端处理程序(处理程序是单例spring bean)。 由于这么小的变化,我不相信new对象的数量会显着增加,因为它以1.35G内​​存结束 JMC堆

更新分别运行netty和springboot项目后,我获得了更多的统计数据:

  1. OS内存8G。 springboot版项目:PS老一代:容量= 195MB; 二手= 47MB; 使用率为24%。 它有692,971个对象,总大小为41,848,384。
  2. OS存储器16G。 netty版项目:PS老一代:容量= 488MB; 使用327MB; 67%使用。 它有1,243,432个对象,总大小为221,427,824。

netty版本:堆转储显示它具有279,255个类io.netty.buffer.PoolSubpage实例,而类似org.springframework.core.MethodClassKey类的第二个最多7,222个实例。 两个版本都有服务(我们自己的类)对象有限,不超过3000。

我试图在4G内存linux上运行-Xmx1024m ,仍然会导致同样的内存不足问题。

您在Windows上看到的行为是正常的GC行为。 应用程序正在生成垃圾,然后您达到导致GC运行的阈值。 GC释放了大量的堆。 然后应用程序再次启动。 结果是堆占用中的锯齿形图案。

这个是正常的。 每个JVM都或多或少地表现得像这样。


Linux上的行为看起来像是在尝试在本机内存中分配大量(77MB),并且由于操作系统拒绝为JVM提供大量内存而失败。 通常会发生这种情况,因为操作系统资源已耗尽; 例如物理RAM,交换空间等

Windows 8G,linux 4G。

这可能解释了它。 您的Linux系统只有Windows系统的一半物理内存。 如果您运行带有大型Java堆的netty并且您的Linux操作系统尚未配置任何交换空间,那么JVM使用所有可用虚拟内存似乎是合理的。 它甚至可能发生在JVM启动时。

(如果我们假设Windows和Linux的最大堆大小设置相同,那么在Windows上至少有4.5GB的虚拟地址空间可供其他东西使用。在Linux上,只有0.5GB。而且0.5GB已经有了保持所有非堆JVM利用率…加上操作系统和各种其他用户空间进程。很容易看出你如何使用所有这些…导致分配失败。)

如果我的理论是正确的,那么解决方案是更改JVM命令行选项以使-Xmx更小。

(或者增加可用的物理/虚拟内存。但是要小心通过添加交换空间来增加虚拟内存。如果虚拟/物理比率太大,你可能会得到虚拟内存“颠簸”,这会导致可怕的性能。)