java堆内存管理内存不足

时间:2018-07-03 06:53:54

标签: java netty

在Linux上运行netty异步服务器和客户端项目时,它耗尽了所有可用的内存,如下所示: linux console

所以我在Windows上运行它,JMC像这样显示堆:

JMC memory

我的问题是:为什么Windows和linux的行为不同,是否可以在某处配置linux jvm以释放堆内存?为什么在Windows(GC)中有堆释放?如何找出占用大量内存的可疑代码?

编辑:linux是4G,windows是8G,但我认为绝对值不会导致运行结果差异。 Project不会直接处理原始的bytebuff,而是将HttpServerCodecHttpObjectAggregator用于bytebuf。在Linux中运行的命令是java -jar xx.jar。我不仅想知道为什么为什么不同,为什么要锯齿,还想知道如何找到占用大量内存的那个。 JMC显示了另一个数字,我不知道为什么线程可以具有如此高的块数。 netty线程IO具有99LINE 71ms。 JMC threads

更新: 现在,我想找到代码的哪一部分占用了很多内存。 JMC堆显示EDEN SPACE很高,我对其进行了配对,发现EDEN SPACE适用于new对象。最初,该项目使用spring-boot,该容器具有tomcat servlet 3.0作为容器和apache httpclient池作为客户端,现在仅使用netty异步服务器和netty异步客户端更改了这些部分,而其余部分仍然保留(仍然使用spring作为豆管理)。 Netty服务器和客户端处理程序对于所有请求都是共享的(处理程序是单例spring Bean)。有了这么小的更改,我不相信new对象的数量会显着增加到以1.35G内​​存JMC heap

结尾

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

  1. OS内存8G。 springboot版本项目:PS Old Generation:容量= 195MB;已用= 47MB;使用了24%。它有692,971个对象,总大小为41,848,384。
  2. OS内存16G。网络版本项目:PS Old Generation:容量= 488MB;已用327MB;使用了67%。它有1,243,432个对象,总大小为221,427,824。

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

我曾尝试在4G内存Linux上使用-Xmx1024m来运行,但仍然会引起同样的内存不足问题。

1 个答案:

答案 0 :(得分:3)

您在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较小。

(或增加可用的物理/虚拟内存。但是要小心通过添加交换空间来增加虚拟内存。如果虚拟/物理比太大,则会使虚拟内存“崩溃”,这可能会导致糟糕的性能。 )