内存泄漏检查

野火这么多年以来基本上没有遇到过内存泄漏问题,唯一一个客户联系不是特别顺畅,只是说内存增长很多,但堆内存没有变化,怀疑是堆外内存泄漏,但后来也失去了联系。我们自己也尝试在本地来复现堆外内存泄漏,包括在我们上线的测试环境中测试,没有办法来复现这个问题。我们怀疑是可能不同JDK发行版本或者是某个linux发行版本差异导致的,但还需要继续处理这个问题。因此我们写下此文档以便有客户出现问题时,能够检查此问题。如果出现内存泄漏问题请及时联系我们。

1. java应用的内存构成

java开发都非常熟悉Xmx,Xms等参数,这个是对JVM的内存的控制。一个Java应用首先是一个Linux应用(假设在linux系统下),其中包含一大块给虚拟机的内存,所有编写的java代码都在这块内存中。但也有例外,可以申请到jvm以外的内存,也就是堆外内存。Javer常见的堆外内存就是Netty的堆外内存。除了这个以外,还可能有些代码使用JNI分配到非堆内存。也有可能使用自定义的classloader使用不到导致占用非堆内存。等等很多可能的原因。

2. Netty堆外内存的检查

Netty有完善的堆外内存检查方法,在野火IM启动脚本wildfirechat.sh 最后一行启动命令中,添加一个参数-Dio.netty.leakDetectionLevel=PARANOID,加完之后的命令可能如下:

$JAVA -server $JAVA_OPTS $JAVA_OPTS_SCRIPT -Dio.netty.leakDetectionLevel=PARANOID  -Dlog4j.configurationFile="file:$LOG_FILE" -Dlog4j2.formatMsgNoLookups=true -Dcom.mchange.v2.c3p0.cfg.xml="$C3P0_CONF_FILE" -Dhazelcast.configuration=$HZ_CONF_FILE -Dwildfirechat.path="$WILDFIRECHAT_CONFIG_PATH" -cp "$WILDFIRECHAT_HOME/lib/*" cn.wildfirechat.server.Server

参数PARANOID会对每一个堆外的内存分配进行跟踪,会消耗一定的资源。如果担心影响正常的业务,可使用参数ADVANCED,这个参数会做1%的抽查,能够做到基本无影响。

当有内存泄漏被检查到时,就会打印到日志中。从日志中搜索LEAK就能看到。

3. NMT(Native Memory Tracking)

JVM提供了Native Memory Tracking(NMT)功能,可以跟踪非JVM管理的内存。在野火IM的启动脚本wildfirechat.sh中,最后一行启动命令之前添加JAVA_OPTS="$JAVA_OPTS -XX:NativeMemoryTracking=detail",用来开启NMT功能。应用运行一段时间进入平稳期后,执行命令jcmd <pid> VM.native_memory detail打印出非堆内存的详细信息并保存。等到问题出现后,再打印出非堆内存的情况,并把这两次的结果发给野火来分析。

4. 开启GC日志

GC日志也会提供一些有效的信息,在野火IM的启动脚本wildfirechat.sh中打开下面这几行配置

JAVA_OPTS="$JAVA_OPTS -XX:+PrintGCDetails"
JAVA_OPTS="$JAVA_OPTS -XX:+PrintGCDateStamps"
JAVA_OPTS="$JAVA_OPTS -XX:+PrintHeapAtGC"

这样在控制台就会打印出GC的详细情况。

5. 业务使用情况

野火提供有非常多的server api和客户端api,大部分客户只用到其中一个子集。所以也不排除是使用了某个不常用接口导致的,所以当出现这个问题后,也需要把野火IM的日志发给我们分析,看一下都调用了哪些接口。

2018 © wildfirechat.net 京ICP备18060403号-1 all right reserved,powered by Gitbook该文件修订时间: 2024-10-08 13:46:18

results matching ""

    No results matching ""