我们有一个线上的项目,刚启动完就占用了使用 top 命令查看 RES 占用了超过 1.5G,这明显不合理,于是进行了一些分析找到了根本的原因,下面是完整的分析过程,希望对你有所帮助。
会涉及到下面这些内容
- Linux 经典的 64M 内存问题
- 堆内存分析、Native 内存分析的基本套路
- tcmalloc、jemalloc 在 native 内存分析中的使用
- finalize 原理
- hibernate 毁人不倦
现象
程序启动的参数
ENV=FAT java
-Xms1g -Xmx1g
-XX:MetaspaceSize=120m
-XX:MaxMetaspaceSize=400m
-XX:+UseConcMarkSweepGC
-jar
EasiCareBroadCastRPC.jar
复制代码
启动后内存占用如下,惊人的 1.5G,Java 是内存大户,但是你也别这么玩啊。
下面是愉快的分析过程。
柿子先挑软的捏
先通过 jcmd 或者 jmap 查看堆内存是否占用比较高,如果是这个问题,那很快就可以解决了。
可以看到堆内存占用 216937K + 284294K = 489.48M,Metaspace 内存虽然不属于 Java 堆,这里也显示了出来占用 80M+,这两部分加起来,远没有到 1.5G。
那剩下的内存去了哪里?到这里,已经可以知道可能是堆以外的部分占用了内存,接下来就是开始使用 NativeMemoryTracking
来进行下一步分析。
NativeMemoryTracking 使用
如果要跟踪其它部分的内存占用,需要通过 -XX:NativeMemoryTracking
来开启这个特性
java -XX:NativeMemoryTracking=[off | summary | detail]
复制代码
加入这个启动参数,重新启动进程,随后使用 jcmd 来打印相关的信息。
$ jcmd `jps | grep -v Jps | awk '{print $1}'` VM.native_memory detail
Total: reserved=2656938KB, committed=1405158KB
- Java Heap (reserved=1048576KB, committed=1048576KB)
(mmap: reserved=1048576KB, committed=1048576KB)
- Class (reserved=1130053KB, committed=90693KB)
(classes #15920)
(malloc=1605KB #13168)
(mmap: reserved=1128448KB, committed=89088KB)
- Thread (reserved=109353KB, committed=109353KB)
(thread #107)
(stack: reserved=108884KB, committed=108884KB)
(malloc=345KB #546)
(arena=124KB #208)
- Code (reserved=257151KB, committed=44731KB)
(malloc=7551KB #9960)
(mmap: reserved=249600KB, committed=37180KB)
- GC (reserved=26209KB, committed=26209KB)
(malloc=22789KB #306)
(mmap: reserved=3420KB, committed=3420KB)
- Compiler (reserved=226KB, committed=226KB)
(malloc=95KB #679)
(arena=131KB #7)
- Internal (reserved=15063KB, committed=15063KB)
(malloc=15031KB #20359)
(mmap: reserved=32KB, committed=32KB)
- Symbol (reserved=22139KB, committed=22139KB)
(malloc=18423KB #196776)
(arena=3716KB #1)
复制代码
很失望,这