java堆内存管理内存不足
java heap memory management insufficient memory
当 netty 异步服务器和客户端项目 运行 在 linux 上运行时,它 运行 耗尽了所有可用内存,如下所示:
所以我 运行 它在 windows 上,JMC 像这样显示堆:
我的问题是:为什么 windows 和 linux 的行为不同,有没有什么地方可以配置 linux jvm 来释放堆内存?为什么在 windows (GC) 中会出现堆释放?如何找出可疑的代码占用这么多内存?
编辑:linux是4G,windows是8G,但我不认为绝对值会导致运行ning结果差异。项目不直接处理原始字节缓冲区,它使用 HttpServerCodec
和 HttpObjectAggregator
作为字节缓冲区。 linux中运行的命令是java -jar xx.jar
。我不仅想知道为什么不同,为什么锯齿而且如何定位占用这么多内存的那个。 JMC又出图了,不知道为什么一个线程可以有这么高的块数。 netty 线程 IO 有 99LINE 71ms。
更新:
现在我想定位是哪部分代码占用了这么多内存。 JMC 堆显示 EDEN SPACE 非常高,我 bing 它发现 EDEN SPACE 用于 new
对象。原来项目使用spring-boot,容器是tomcatservlet 3.0,客户端是apache httpclient pool,现在改成netty异步server和netty异步client,其他的都改了零件仍然存在(仍然使用 spring 进行 bean 管理)。 Netty 服务器和客户端处理程序为所有请求共享(处理程序是单例 spring beans)。有了这么小的变化,我不相信 new
对象的数量会显着增加到 1.35G 内存
UPDATE分别运行ning netty和springboot项目后,得到更多的统计数据:
- OS内存8G。 spring启动版项目:PS老年代:容量=195MB;使用=47MB;使用了 24%。它有 692,971 个对象,总大小为 41,848,384。
- OS内存16G。 netty 版本项目:PS 老年代:capacity = 488MB;已用 327MB;使用了 67%。它有 1,243,432 个对象,总大小为 221,427,824。
netty 版本:堆转储显示它有 279,255 个 class io.netty.buffer.PoolSubpage
实例,而第二多的 class org.springframework.core.MethodClassKey
实例为 7,222 个实例。两个版本都有服务(我们自己的class)对象限制,不超过3000个。
我已经尝试在 4G 内存 linux 上 运行 和 -Xmx1024m
,仍然会导致同样的内存不足问题。
您在 Windows 上看到的行为是正常的 GC 行为。应用程序正在生成垃圾,然后您达到了导致 GC 运行 的阈值。 GC 释放了大量堆。然后应用程序再次启动。结果是堆占用中的锯齿模式。
这是正常的。每个 JVM 的行为或多或少都是这样。
Linux 上的行为看起来像是在尝试在本机内存中分配较大的内容 (77MB),但失败了,因为 OS 拒绝为 JVM 提供那么多的内存。通常发生这种情况是因为 OS 资源不足 运行;例如物理 RAM,交换 space,等等
Windows 8G, linux 4G.
这可能解释了它。您的 Linux 系统只有 Windows 系统的一半物理内存。如果你 运行ning netty 有一个大的 Java 堆并且你的 Linux OS 没有配置任何交换 space,那么这似乎是合理的JVM 正在使用所有可用的虚拟内存。它甚至可能在 JVM 启动时发生。
(如果我们假设 Windows 和 Linux 的最大堆大小设置相同,那么在 Windows 上至少有 4.5GB 的虚拟地址 space 可用于其他事情。在 Linux 上,只有 0.5GB。而这 0.5GB 必须容纳所有非堆 JVM 利用率...加上 OS 和各种其他用户- space 个进程。很容易看出您如何使用所有这些...导致分配失败。)
如果我的理论是正确的,那么解决方案就是更改 JVM 命令行选项,使 -Xmx 变小。
(或者增加可用的物理/虚拟内存。但是通过添加交换 space 来增加虚拟内存时要小心。如果 virtual/physical 比率太大,您可以获得虚拟内存 "thrashing" 这会导致糟糕的性能。)
当 netty 异步服务器和客户端项目 运行 在 linux 上运行时,它 运行 耗尽了所有可用内存,如下所示:
所以我 运行 它在 windows 上,JMC 像这样显示堆:
我的问题是:为什么 windows 和 linux 的行为不同,有没有什么地方可以配置 linux jvm 来释放堆内存?为什么在 windows (GC) 中会出现堆释放?如何找出可疑的代码占用这么多内存?
编辑:linux是4G,windows是8G,但我不认为绝对值会导致运行ning结果差异。项目不直接处理原始字节缓冲区,它使用 HttpServerCodec
和 HttpObjectAggregator
作为字节缓冲区。 linux中运行的命令是java -jar xx.jar
。我不仅想知道为什么不同,为什么锯齿而且如何定位占用这么多内存的那个。 JMC又出图了,不知道为什么一个线程可以有这么高的块数。 netty 线程 IO 有 99LINE 71ms。
更新:
现在我想定位是哪部分代码占用了这么多内存。 JMC 堆显示 EDEN SPACE 非常高,我 bing 它发现 EDEN SPACE 用于 new
对象。原来项目使用spring-boot,容器是tomcatservlet 3.0,客户端是apache httpclient pool,现在改成netty异步server和netty异步client,其他的都改了零件仍然存在(仍然使用 spring 进行 bean 管理)。 Netty 服务器和客户端处理程序为所有请求共享(处理程序是单例 spring beans)。有了这么小的变化,我不相信 new
对象的数量会显着增加到 1.35G 内存
UPDATE分别运行ning netty和springboot项目后,得到更多的统计数据:
- OS内存8G。 spring启动版项目:PS老年代:容量=195MB;使用=47MB;使用了 24%。它有 692,971 个对象,总大小为 41,848,384。
- OS内存16G。 netty 版本项目:PS 老年代:capacity = 488MB;已用 327MB;使用了 67%。它有 1,243,432 个对象,总大小为 221,427,824。
netty 版本:堆转储显示它有 279,255 个 class io.netty.buffer.PoolSubpage
实例,而第二多的 class org.springframework.core.MethodClassKey
实例为 7,222 个实例。两个版本都有服务(我们自己的class)对象限制,不超过3000个。
我已经尝试在 4G 内存 linux 上 运行 和 -Xmx1024m
,仍然会导致同样的内存不足问题。
您在 Windows 上看到的行为是正常的 GC 行为。应用程序正在生成垃圾,然后您达到了导致 GC 运行 的阈值。 GC 释放了大量堆。然后应用程序再次启动。结果是堆占用中的锯齿模式。
这是正常的。每个 JVM 的行为或多或少都是这样。
Linux 上的行为看起来像是在尝试在本机内存中分配较大的内容 (77MB),但失败了,因为 OS 拒绝为 JVM 提供那么多的内存。通常发生这种情况是因为 OS 资源不足 运行;例如物理 RAM,交换 space,等等
Windows 8G, linux 4G.
这可能解释了它。您的 Linux 系统只有 Windows 系统的一半物理内存。如果你 运行ning netty 有一个大的 Java 堆并且你的 Linux OS 没有配置任何交换 space,那么这似乎是合理的JVM 正在使用所有可用的虚拟内存。它甚至可能在 JVM 启动时发生。
(如果我们假设 Windows 和 Linux 的最大堆大小设置相同,那么在 Windows 上至少有 4.5GB 的虚拟地址 space 可用于其他事情。在 Linux 上,只有 0.5GB。而这 0.5GB 必须容纳所有非堆 JVM 利用率...加上 OS 和各种其他用户- space 个进程。很容易看出您如何使用所有这些...导致分配失败。)
如果我的理论是正确的,那么解决方案就是更改 JVM 命令行选项,使 -Xmx 变小。
(或者增加可用的物理/虚拟内存。但是通过添加交换 space 来增加虚拟内存时要小心。如果 virtual/physical 比率太大,您可以获得虚拟内存 "thrashing" 这会导致糟糕的性能。)