2

java 堆外内存

 2 years ago
source link: https://caorong.github.io/2020/04/12/java-direct-memory/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

这篇文章将整理一下java 堆外内存的问题的一些常用处理方法。

java 内存占用盘点

java 实际会使用内存情况如下

堆内 线程栈 方法区 二进制代码 堆外
xmx 线程数 x xss 存储类定义以及常量池 jit多层编译代码 被netty或其他堆外缓存使用

注意: 只有除了堆内,其他内存都占用的堆外内存, 他们都算整个java进程占用的内存,但无法被类似 jmap,mat 等堆内分析工具分析。

使用NMT 追踪 JVM 自用的堆外内存情况

NMT是Java7U40引入的HotSpot新特性,可用于监控JVM原生内存的使用,但比较可惜的是,目前的NMT不能监控到JVM之外或原生库分配的内存

使用方式,需要在jvm 启动时加上参数, (注意: 据官方文档开启该功能会影响 5%-10% 的性能)

配置方式:

-XX:NativeMemoryTracking=summary 或者 -XX:NativeMemoryTracking=detail

查询方式:

jcmd <pid> VM.native_memory [summary | detail | baseline | summary.diff | detail.diff
jcmd 35740 VM.native_memory summary
35740:

Native Memory Tracking:

Total: reserved=3516019KB, committed=244959KB
堆内
- Java Heap (reserved=2097152KB, committed=131072KB)
(mmap: reserved=2097152KB, committed=131072KB)

类数据
- Class (reserved=1062038KB, committed=10518KB)
(classes #873)
(malloc=5270KB #462)
(mmap: reserved=1056768KB, committed=5248KB)

线程栈所占空间
- Thread (reserved=16453KB, committed=16453KB)
(thread #17)
(stack: reserved=16384KB, committed=16384KB)
(malloc=49KB #86)
(arena=20KB #33)

生成代码
- Code (reserved=249803KB, committed=2739KB)
(malloc=203KB #651)
(mmap: reserved=249600KB, committed=2536KB)

gc 占用的空间 比如 card table
- GC (reserved=82395KB, committed=75999KB)
(malloc=5771KB #121)
(mmap: reserved=76624KB, committed=70228KB)

编译生成代码时所占用的空间
- Compiler (reserved=138KB, committed=138KB)
(malloc=7KB #41)
(arena=131KB #3)

其他内部内存 command line parser, JVMTI, properties and so on
- Internal (reserved=5787KB, committed=5787KB)
(malloc=5755KB #2844)
(mmap: reserved=32KB, committed=32KB)

Symbol:保留字符串(Interned String)的引用与符号表引用放在这里
- Symbol (reserved=1962KB, committed=1962KB)
(malloc=1250KB #2173)
(arena=712KB #1)

本NMT 工具自己所需内存
- Native Memory Tracking (reserved=105KB, committed=105KB)
(malloc=3KB #41)
(tracking overhead=101KB)

文档未提及
- Arena Chunk (reserved=187KB, committed=187KB)
(malloc=187KB)

各项解释的官方文档

保留内存(reserved):reserved memory 是指JVM 通过mmaped PROT_NONE 申请的虚拟地址空间,在页表中已经存在了记录(entries),保证了其他进程不会被占用,且保证了逻辑地址的连续性,能简化指针运算。

提交内存(commited):committed memory 是JVM向操做系统实际分配的内存(malloc/mmap),mmaped PROT_READ | PROT_WRITE,仍然会page faults,但是跟 reserved 不同,完全内核处理像什么也没发生一样。

其他内部内存 (Internal): 注意 Netty 使用的 ByteBuffer.allocateDirect 内部调用的 Unsafe.allocateMemory 内部其实会被 NMT 收集为 Internal 分类。

但是 MappedByteBuffers( 由 FileChannel.map 触发) 则不会被 NMT 收集到。但却会被操作系统收集。

所以,对于这个堆外内存的监控,jcmd 还不够,得上后续linux 的通用进程 内存分析工具。

这里需要注意的是:由于malloc/mmap的lazy allocation and paging机制,即使是commited的内存,也不一定会真正分配物理内存。

自用堆外内存如何追踪

使用pmap 工具查看进程内存占用

pmap -x {pid}

[root@test-b12-java-3-52 ~]# pmap -x 140087
140087: /usr/j2sdk/jdk1.8.0_191/bin/java -Djava.util.logging.config.file=/root/apache-tomcat-xxx
Address Kbytes RSS Dirty Mode Mapping
0000000000400000 4 0 0 r-x-- java
0000000000600000 4 4 4 r---- java
0000000000601000 4 4 4 rw--- java
00000000007d9000 580 508 508 rw--- [ anon ]
0000000080000000 2105236 2105044 2105044 rw--- [ anon ]
...
00007fc21b3aa000 4 4 4 rw--- [ anon ]
00007ffd9291e000 84 44 44 rw--- [ stack ]
00007ffd92972000 4 4 0 r-x-- [ anon ]
ffffffffff600000 4 0 0 r-x-- [ anon ]
---------------- ------ ------ ------
total kB 16462260 3103136 3096156

可见上述进程 实际占用内存 rss 大约3G

pmap命令内部实际是读取了/proc/pid/maps和/porc/pid/smaps文件来输出。

使用strace 监控下内存分配和回收的系统调用

strace -o xxx.txt -T -tt -e mmap,munmap,mprotect -fp 12

140140 23:00:00.624788 mprotect(0x7fc21b3a5000, 4096, PROT_READ) = 0 <0.000205>
140140 23:00:00.625226 mprotect(0x7fc21b3a5000, 4096, PROT_READ|PROT_WRITE) = 0 <0.000168>
140140 23:00:00.625604 mprotect(0x7fc21b3a6000, 4096, PROT_NONE) = 0 <0.000189>
140140 23:00:00.688019 mprotect(0x7fc21b3a6000, 4096, PROT_READ) = 0 <0.000161>
140140 23:00:12.897296 mprotect(0x7fc21b3a5000, 4096, PROT_READ) = 0 <0.000374>
142593 23:00:12.898044 --- SIGSEGV {si_signo=SIGSEGV, si_code=SEGV_ACCERR, si_addr=0x7fc21b3a5880} ---
20726 23:00:12.898063 --- SIGSEGV {si_signo=SIGSEGV, si_code=SEGV_ACCERR, si_addr=0x7fc21b3a5480} ---
140140 23:00:12.898075 mprotect(0x7fc21b3a5000, 4096, PROT_READ|PROT_WRITE) = 0 <0.000266>
140140 23:00:12.899591 mprotect(0x7fc21b3a6000, 4096, PROT_NONE) = 0 <0.000250>
140140 23:00:12.905392 mprotect(0x7fc21b3a6000, 4096, PROT_READ) = 0 <0.000115>
140140 23:00:13.101242 mprotect(0x7fc21b3a5000, 4096, PROT_READ) = 0 <0.000272>
140140 23:00:13.101815 mprotect(0x7fc21b3a5000, 4096, PROT_READ|PROT_WRITE) = 0 <0.000235>
140140 23:00:13.102247 mprotect(0x7fc21b3a6000, 4096, PROT_NONE) = 0 <0.000149>
140140 23:00:13.158721 mprotect(0x7fc21b3a6000, 4096, PROT_READ) = 0 <0.000213>
142592 23:00:13.177198 mmap(NULL, 44793, PROT_READ, MAP_SHARED, 96, 0x84000) = 0x7fc1fc068000 <0.000400>
142592 23:00:13.181533 munmap(0x7fc1fc068000, 44793) = 0 <0.000445>
142592 23:00:13.246486 mmap(NULL, 44793, PROT_READ, MAP_SHARED, 96, 0x84000) = 0x7fc1fc068000 <0.000381>

https://blog.csdn.net/qianshangding0708/article/details/100978730

https://stackoverflow.com/questions/47309859/what-is-contained-in-code-internal-sections-of-jcmd

https://docs.oracle.com/javase/8/docs/technotes/guides/troubleshoot/tooldescr007.html

https://docs.oracle.com/javase/8/docs/technotes/guides/troubleshoot/tooldescr022.html#BABHIFJC

http://hg.openjdk.java.net/jdk8u/jdk8u/hotspot/file/a9b412abe617/src/share/vm/memory/allocation.hpp#l147

https://www.baeldung.com/java-stack-heap


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK