Java进程内存组成

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 看出具体的内存占用。

参考

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容