【视频笔记】JVM内存越来越高,查了2周,发现是堆外内存泄露!
top查看负载情况

检查堆与非堆
通过jcmd与jstat观察JVM堆使用情况

## jcmd pid GC.heap_info
[service@localhost ~]$ jcmd 11264 GC.heap_info
11264:
def new generation total 4928K, used 795K [0x00000000f0a00000, 0x00000000f0f50000, 0x00000000f5c00000)
eden space 4416K, 18% used [0x00000000f0a00000, 0x00000000f0ac6cb8, 0x00000000f0e50000)
from space 512K, 0% used [0x00000000f0e50000, 0x00000000f0e50000, 0x00000000f0ed0000)
to space 512K, 0% used [0x00000000f0ed0000, 0x00000000f0ed0000, 0x00000000f0f50000)
tenured generation total 10944K, used 0K [0x00000000f5c00000, 0x00000000f66b0000, 0x0000000100000000)
the space 10944K, 0% used [0x00000000f5c00000, 0x00000000f5c00000, 0x00000000f5c00200, 0x00000000f66b0000)
Metaspace used 127K, committed 320K, reserved 1114112K
class space used 3K, committed 128K, reserved 1048576K
## jstat -gcutil pid 时间间隔
[service@localhost ~]$ jstat -gcutil 11264 3000
S0 S1 E O M CCS YGC YGCT FGC FGCT CGC CGCT GCT
0.00 0.00 18.01 0.00 - - 0 0.000 0 0.000 - - 0.000
## jcmd其他参数,可以通过jcmd pid help显示
[service@localhost ~]$ jcmd 11264
11264:
The following commands are available:
Compiler.CodeHeap_Analytics
Compiler.codecache
Compiler.codelist
Compiler.directives_add
Compiler.directives_clear
Compiler.directives_print
Compiler.directives_remove
Compiler.perfmap
Compiler.queue
GC.class_histogram
GC.finalizer_info
GC.heap_dump
GC.heap_info
GC.run
GC.run_finalization
JFR.check
JFR.configure
JFR.dump
JFR.start
JFR.stop
JVMTI.agent_load
JVMTI.data_dump
ManagementAgent.start
ManagementAgent.start_local
ManagementAgent.status
ManagementAgent.stop
System.native_heap_info
System.trim_native_heap
Thread.print
VM.cds
VM.class_hierarchy
VM.classloader_stats
VM.classloaders
VM.command_line
VM.dynlibs
VM.events
VM.flags
VM.info
VM.log
VM.metaspace
VM.native_memory
VM.print_touched_methods
VM.set_flag
VM.stringtable
VM.symboltable
VM.system_properties
VM.systemdictionary
VM.uptime
VM.version
help
#通过arthas查看metaspace(元空间)、direct等非堆内存占用
堆与非堆内存都正常,如果有内存泄漏,那只能是堆外的native内存了

本地执行arthas memory命令

Linux进程的内存布局

pmap查看进程的内存布局

pmap收集内存布局,比较内存布局的不同

icdiff命令比较数据差异(本地centos好像没有这个命令)

检查native内存

strings命令,less -S命令



其他方法:
开启JVM的NMT原生内存追踪
检查被glibc内存分配器缓存的内存
使用tcmalloc或jemalloc的内存泄漏检测工具

NMT只能观察到JVM管理的内存,像通过JNI机制直接调用malloc分配的内存,则感知不到

libc实现了类似内存池的机制,在free函数调用时将内存块缓存起来不归还给linux,缓存达到一定阈值才会实际执行归还内存的系统调用(这个阈值在哪里配?可以配多大??)

malloc_stats: glibc提供此函数,可用于检查glibc缓存的内存情况
# 查看glibc内存分配情况,会输出到进程标准错误中
gdb -q -batch -ex 'call malloc_stats()' -p 1

检查被glibc内存分配器缓存的内存
malloc_trim: glibc提供此函数,可用于回收缓存的内存。
# 回收glibc缓存的内存
gdb -q -batch -ex 'call malloc_trim(0)' -p 4510

使用Linux的LD_PRELOAD机制,可将glibc的内存分配器更换为tcmall或者jemalloc,他们提供了内存泄漏检测的功能


评论摘录
jstat -gcutil后的这张图里面的S1被占满了,这个没有问题吗 作者可以说明下吗
没有问题,G1收集器会一直是100%
浙公网安备 33010602011771号