在Linux上运行netty异步服务器和客户端项目时,它耗尽了所有可用的内存,如下所示:
所以我在Windows上运行它,JMC像这样显示堆:
我的问题是:为什么Windows和linux的行为不同,是否可以在某处配置linux jvm以释放堆内存?为什么在Windows(GC)中有堆释放?如何找出占用大量内存的可疑代码?
编辑:linux是4G,windows是8G,但我认为绝对值不会导致运行结果差异。 Project不会直接处理原始的bytebuff,而是将HttpServerCodec
和HttpObjectAggregator
用于bytebuf。在Linux中运行的命令是java -jar xx.jar
。我不仅想知道为什么为什么不同,为什么要锯齿,还想知道如何找到占用大量内存的那个。 JMC显示了另一个数字,我不知道为什么线程可以具有如此高的块数。 netty线程IO具有99LINE 71ms。
更新:
现在,我想找到代码的哪一部分占用了很多内存。 JMC堆显示EDEN SPACE很高,我对其进行了配对,发现EDEN SPACE适用于new
对象。最初,该项目使用spring-boot,该容器具有tomcat servlet 3.0作为容器和apache httpclient池作为客户端,现在仅使用netty异步服务器和netty异步客户端更改了这些部分,而其余部分仍然保留(仍然使用spring作为豆管理)。 Netty服务器和客户端处理程序对于所有请求都是共享的(处理程序是单例spring Bean)。有了这么小的更改,我不相信new
对象的数量会显着增加到以1.35G内存
更新分别运行netty和springboot项目后,我得到了更多的统计数据:
网络版本:堆转储显示它具有279,255个类io.netty.buffer.PoolSubpage
的实例,而第二个最多7,222个类org.springframework.core.MethodClassKey
的实例。这两个版本的服务对象(我们自己的类)都受到限制,最多不能超过3000个。
我曾尝试在4G内存Linux上使用-Xmx1024m
来运行,但仍然会引起同样的内存不足问题。
答案 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较小。
(或增加可用的物理/虚拟内存。但是要小心通过添加交换空间来增加虚拟内存。如果虚拟/物理比太大,则会使虚拟内存“崩溃”,这可能会导致糟糕的性能。 )