diff --git a/md/SUMMARY.md b/md/SUMMARY.md index 9f949efc..4d00124c 100644 --- a/md/SUMMARY.md +++ b/md/SUMMARY.md @@ -184,3 +184,4 @@ * [音视频高级版的单端口化和强制TCP化](blogs/音视频高级版的单端口化和强制TCP化.md) * [数据库重复消息ID的问题](blogs/数据库重复消息ID的问题.md) * [物联网设备的接入](blogs/物联网设备的接入.md) + * [内存泄漏排查](blogs/内存泄漏排查.md) diff --git a/md/blogs/README.md b/md/blogs/README.md index 76f7ae47..432d84fe 100644 --- a/md/blogs/README.md +++ b/md/blogs/README.md @@ -52,3 +52,4 @@ * [超级群组](超级群组.md) * [音视频高级版的单端口化和强制TCP化](音视频高级版的单端口化和强制TCP化.md) * [物联网设备的接入](物联网设备的接入.md) +* [内存泄漏排查](内存泄漏排查.md) diff --git "a/md/blogs/\345\206\205\345\255\230\346\263\204\346\274\217\346\216\222\346\237\245.md" "b/md/blogs/\345\206\205\345\255\230\346\263\204\346\274\217\346\216\222\346\237\245.md" new file mode 100644 index 00000000..65154418 --- /dev/null +++ "b/md/blogs/\345\206\205\345\255\230\346\263\204\346\274\217\346\216\222\346\237\245.md" @@ -0,0 +1,29 @@ +# 内存泄漏检查 +野火这么多年以来基本上没有遇到过内存泄漏问题,唯一一个客户联系不是特别顺畅,只是说内存增长很多,但堆内存没有变化,怀疑是堆外内存泄漏,但后来也失去了联系。我们自己也尝试在本地来复现堆外内存泄漏,包括在我们上线的测试环境中测试,没有办法来复现这个问题。我们怀疑是可能不同JDK发行版本或者是某个linux发行版本差异导致的,但还需要继续处理这个问题。因此我们写下此文档以便有客户出现问题时,能够检查此问题。如果出现内存泄漏问题请及时联系我们。 + +## java应用的内存构成 +java开发都非常熟悉Xmx,Xms等参数,这个是对JVM的内存的控制。一个Java应用首先是一个Linux应用(假设在linux系统下),其中包含一大块给虚拟机的内存,所有编写的java代码都在这块内存中。但也有例外,可以申请到jvm以外的内存,也就是堆外内存。Javer常见的堆外内存就是Netty的堆外内存。除了这个以外,还可能有些代码使用JNI分配到非堆内存。也有可能使用自定义的classloader使用不到导致占用非堆内存。等等很多可能的原因。 + +## 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```就能看到。 + +## NMT(Native Memory Tracking) +JVM提供了Native Memory Tracking(NMT)功能,可以跟踪非JVM管理的内存。在野火IM的启动脚本```wildfirechat.sh```中,最后一行启动命令之前添加```JAVA_OPTS="$JAVA_OPTS -XX:NativeMemoryTracking=detail"```,用来开启NMT功能。应用运行一段时间进入平稳期后,执行命令```jcmd VM.native_memory detail```打印出非堆内存的详细信息并保存。等到问题出现后,再打印出非堆内存的情况,并把这两次的结果发给野火来分析。 + +## 开启GC日志 +GC日志也会提供一些有效的信息,在野火IM的启动脚本```wildfirechat.sh```中打开下面这几行配置 +``` +JAVA_OPTS="$JAVA_OPTS -XX:+PrintGCDetails" +JAVA_OPTS="$JAVA_OPTS -XX:+PrintGCDateStamps" +JAVA_OPTS="$JAVA_OPTS -XX:+PrintHeapAtGC" +``` +这样在控制台就会打印出GC的详细情况。 + +## 业务使用情况 +野火提供有非常多的server api和客户端api,大部分客户只用到其中一个子集。所以也不排除是使用了某个不常用接口导致的,所以当出现这个问题后,也需要把野火IM的日志发给我们分析,看一下都调用了哪些接口。