1.组成部分
Java内存分为两部分:
- 堆内存
堆内存由GC垃圾回收期进行管理。 - 非堆内存
非堆内存包括:Java方法栈、本地方法栈、元空间Metaspace、直接内存、代码缓存、GC垃圾回收期占用内存、符号表
2.jcmd命令
[xxxxx xxx@xxxx-001:/data/br/xxx/xxxx]$ jcmd 1 VM.native_memory summary
1:
Native Memory Tracking:
Total: reserved=4119234KB, committed=2609862KB
- Java Heap (reserved=2097152KB, committed=1776640KB)
(mmap: reserved=2097152KB, committed=1776640KB)
- Class (reserved=1196169KB, committed=165257KB)
(classes #25502)
(malloc=4233KB #56812)
(mmap: reserved=1191936KB, committed=161024KB)
- Thread (reserved=266542KB, committed=266542KB)
(thread #260)
(stack: reserved=265384KB, committed=265384KB)
(malloc=853KB #1302)
(arena=305KB #519)
- Code (reserved=272911KB, committed=130951KB)
(malloc=23311KB #26777)
(mmap: reserved=249600KB, committed=107640KB)
- GC (reserved=134686KB, committed=122798KB)
(malloc=24094KB #68976)
(mmap: reserved=110592KB, committed=98704KB)
- Compiler (reserved=1063KB, committed=1063KB)
(malloc=932KB #2433)
(arena=131KB #3)
- Internal (reserved=104282KB, committed=104278KB)
(malloc=104246KB #141164)
(mmap: reserved=36KB, committed=32KB)
- Symbol (reserved=32574KB, committed=32574KB)
(malloc=30105KB #311251)
(arena=2469KB #1)
- Native Memory Tracking (reserved=9564KB, committed=9564KB)
(malloc=37KB #417)
(tracking overhead=9527KB)
- Arena Chunk (reserved=195KB, committed=195KB)
(malloc=195KB)
- Unknown (reserved=4096KB, committed=0KB)
(mmap: reserved=4096KB, committed=0KB)
内存占用方式含义:
- reserved :操作系统已经为该进程“保留”的。所谓的保留,更加接近一种记账的概念,就是操作系统承诺最多可以给你多少资源,到时候并不一定能申请的到。
- used:你当前正在使用的有多少资源。
- committed:进程已经申请进的内存,可能在被使用,有可能闲置着。used<=committed
各组成部分的介绍:
- 元空间,JVM 将类文件加载到内存中用于后续使用占用的空间,注意是 JVM C++ 层面的内存占用,主要包括类文件中在 JVM 解析为 C++ 的 Klass 类以及相关元素。对应的 Java 反射类 Class 还是在堆内存空间中
- C++ 字符串即符号(Symbol)占用空间,前面加载类的时候,其实里面有很多字符串信息(注意不是 Java 字符串,是 JVM 层面 C++ 字符串),不同类的字符串信息可能会重复。所以统一放入符号表(Symbol table)复用。元空间中保存的是针对符号表中符号的引用。
- 线程占用内存,主要是每个线程的线程栈,我们也只会主要分析线程栈占用空间
- JIT编译器本身占用的空间以及JIT编译器编译后的代码占用空间
- Arena 数据结构占用空间,我们看到 Native Memory Tracking 中有很多通过 arena 分配的内存,这个就是管理 Arena 数据结构占用空间。
- JVM GC需要的数据结构与记录信息占用的空间,这块内存可能会比较大,尤其是对于那种专注于低延迟的 GC,例如 ZGC。其实 ZGC 是一种以空间换时间的思路,提高 CPU 消耗与内存占用,但是消灭全局暂停。之后的 ZGC 优化方向就是尽量降低 CPU 消耗与内存占用,相当于提高了性价比。
- JVM内部(不属于其他类的占用就会归到这一类)与其他占用(不是 JVM 本身而是操作系统的某些系统调用导致额外占的空间)
- 开启 Native Memory Tracking 本身消耗的内存
不能仅通过 Native Memory Tracking 的数据就判断 JVM 占用的内存,因为JVM 通过 mmap 分配的大量内存都是先 reserve 再 commit 之后实际往里面写入数据的时候,才会真正分配物理内存。同时,JVM 还会动态释放一些内存,这些内存可能不会立刻被操作系统回收。Native Memory Tracking 是 JVM 认为自己向操作系统申请的内存,与实际操作系统分配的内存是有所差距的,所以不能只查看 Native Memory Tracking 去判断,我们还需要查看能体现真正内存占用指标。这里可以查看 linux 进程监控文件 smaps_rollup 看出具体的内存占用。
参考
- https://docs.oracle.com/javase/8/docs/technotes/guides/troubleshoot/tooldescr007.html
- https://blog.csdn.net/jiangguilong2000/article/details/131013871
- https://juejin.cn/post/7225871227743043644
- Oracle 提供的内存分析工具:(包括JVM内存)
https://docs.oracle.com/javase/8/docs/technotes/guides/troubleshoot/tooldescr007.html#BABGFCDA
- Oracle 提供的内存分析工具:(包括JVM内存)
- 监控JVM堆和其他内存的工具jstat(主要是堆内存和Metaspace等)
https://docs.oracle.com/javase/8/docs/technotes/tools/unix/jstat.html
- 监控JVM堆和其他内存的工具jstat(主要是堆内存和Metaspace等)
- 解释JVM内存占用机制和内存模型的很好参考
http://www.ibm.com/developerworks/java/library/j-nativememory-linux/
- 解释JVM内存占用机制和内存模型的很好参考
- oracle jre 8的内存模型变化(Metaspace)
http://www.infoq.com/articles/Java-PERMGEN-Removed
https://blogs.oracle.com/poonam/entry/about_g1_garbage_collector_permanent
- oracle jre 8的内存模型变化(Metaspace)
- jvm启动参数参考(包含GC优化参数)
https://docs.oracle.com/javase/8/docs/technotes/tools/windows/java.html
- jvm启动参数参考(包含GC优化参数)
- JVM committed内存和RSS内存的关系
解释为什么java committed总和大于RSS: http://stackoverflow.com/questions/31071019/does-rss-tracks-reserved-or-commited-memory
解释为什么java committed总和小于RSS:(J ,两种情况都会发生) http://stackoverflow.com/questions/31173374/why-does-a-jvm-report-more-committed-memory-than-the-linux-process-resident-set
- JVM committed内存和RSS内存的关系
- 使用反射的时候可能存在本地内存的使用说明
http://www-01.ibm.com/support/docview.wss?uid=swg21566549(有点老和错误)
https://blogs.oracle.com/buck/entry/inflation_system_properties (Oracle JDK,测试结果这里面的是正确的)
- 使用反射的时候可能存在本地内存的使用说明