WAS典型故障案例:DirectByteBuffer占用本地内存高
故障现象
java 进程(PID:21889322) 的CPU 以及内存使用率突然增高,随后 CPU 恢复正常,但是内存一直保持较高状态。CPU 最高达到 34%,内存最高占用 17G。
分析过程
WAS 版本为:8.0.0.6,OS 版本为:AIX6.1
通过javacore.20151208.112729.21889332.0001.txt 查看内存状态,整个 JVM 占用内存大概 12G,其中堆内存占用 3G,本地堆内存占用高达 9G 左右;而其中DirectByteBuffer 占用为 8G。因此判断主要问题在于DirectByteBuffer 占用本地内存偏高,并且使用后长时间没有释放。
1MEMUSER JRE: 12,641,858,008 bytes / 803964 allocations
……
5MEMUSER| | | +--Direct Byte Buffers: 8,443,918,272 bytes / 683183 allocations
判断应用执行了类似 Download Log 的操作,该操作需要向WAS 申请Buffer 便于输出流操作,由于WAS 使用的 NIO( 异步 IO) 模式, 因此申请 Buffer 使用的是DirectByteBuffer 的模式。DBB 的特点是:使用本地堆内存,但是他的回收机制是通过对象虚引用,使用 java 堆的 gc 方式回收内存。并且 DirectByteBuffer 是需要进行system.gc() 来实现清理工作的。
解决方案
◆去掉 WAS 的 JVM 参数 -Xdisableexplicitgc, 该参数会禁用掉所有 system.gc() 的操作。
◆使用 -XX:MaxDirectMemorySize=$bytes 参数, 控制 DirectByteBuffer 的数量。
◆将 WebContainer channelwritetype 的值改为async。