作者 | javaadu

责编 | 郭芮

出品 | CSDN 博客

Java进程使用的虚拟内存确实比Java Heap要大很多。JVM包括很多子系统:垃圾收集器、类加载系统、JIT编译器等等,这些子系统各自都需要一定数量的RAM才能正常工作。

当一个Java进程运行时,也不仅仅是JVM在消耗RAM,很多本地库(Java类库中引用的本地库)可能需要分配原生内存,这些内存无法被JVM的Native Memory Tracking机制监控到。Java应用自身也可能通过DirectByteBuffers等类来使用堆外内存。

那么,当一个Java进程运行时,有哪些部分在消耗内存呢?这里我们只展示哪些可以被Native Memory Tracking监控到的部分。

JVM部分

Java Heap:最明显的部分,Java对象在这个区域分配和回收,Heap的最大值由-Xmx决定。

Garbage Collector:GC的数据结构和算法需要额外的内存对堆内存进行管理。这些数据结构包括:Mark Bitmap、Mark Stack(用于跟踪存活的对象)、Remembered Sets(用于记录region之间的引用)等等。这些数据结构中的一些是可以直接调整的,例如:-XX:MarkStackSizeMax,其他的则依赖于堆的分布,例如:分区大小,-XX:G1HeapRegionSize,这个值越大Remembered Sets的值越小。不同的GC算法需要的额外内存是不同的,-XX: UseSerialGC和-XX: UseShenandoahGC需要较小的额外内存,G1和CMS则需要Heap size的10%作为额外内存。

Code Cache:用于存放动态生成的代码:JIT编译的方法、拦截器和运行时存根。这个区域的大小由-XX:ReservedCodeCacheSize确定(默认是240M)。使用-XX-TieredCompilation关掉多层编译,可以减少需要编译的代码,从而减少Code Cache的使用。

Compiler:JIT编译器需要一些内存来才能工作。这个值可以通过关闭多层编译或减少执行编译的线程数(-XX:CICompilerCount)来调整.

Class loading:类的元数据(方法的字节码、符号表、常量池、注解等)被存放在off-heap区域,也叫Metaspace。当前JVM进程加载了越多的类,就会使用越多的metaspace。通过设置-XX:MaxMetaspaceSize(默认是无限)或-XX:CompressedClassSpaceSize(默认是1G)可以限制元空间的大小。

Symbol tables:JVM中维护了两个重要的哈希表:Symbol表包括类、方法、接口等语言元素的名称、签名、ID等,String table记录了被interned过的字符串的引用。如果Native Tracking表明String table使用了很大的内存,那么说明该Java应用存在对String.intern方法的滥用。

Threads:线程栈也会使用RAM,栈的大小由-Xss确定。默认是1个线程最大有1M的线程栈,幸运得失事情并没有这么糟糕——OS使用惰性策略分配内存页,实际上每个Java线程使用的RAM很小(一般80~200K),作者使用这个脚本(https://github.com/apangin/jstackmem)来统计有多少RSS空间是属于Java线程的。

堆外内存(Direct buffers)

Java应用可以通过ByteBuffer.allocateDirect显式申请堆外内存;默认的堆外内存大小是-Xmx,但是这个值可被-XX:MaxDirectMemorySize覆盖。在JDK11之前,Direct ByteBuffers被NMT(Native Memory Tracking)列举在other部分,可以通过JMC观察到堆外内存的使用情况。

除了DirectByteBuffers,MappedByteBuffers也会使用本地内存,MappedByteBuffers的作用是将文件内容映射到进程的虚拟内存中,NMT没有跟踪它们,想要限制这部分的大小并不容易,可以通过pmap -x 命令观察当前进程使用的实际大小:

1Address           Kbytes    RSS    Dirty Mode  Mapping
2...
300007f2b3e557000   39592   32956       0 r--s- some-file-17405-Index.db
400007f2b40c01000   39600   33092       0 r--s- some-file-17404-Index.db

本地库(Native libraries)

由System.loadLibrary加载的JNI代码也会按需分配RAM,并且这部分内存不受JVM管理。在这里需要关注的是Java类库,未关闭的Java资源会导致本地内存泄漏,典型的例子是:ZipInputStream或DirectoryStream。

JVMTI agent,特别是jdwp调试agent,也可能导致内存的过量使用(PS:去年写memory agent代码造成的内存泄漏记忆犹新)。

Allocator issues

一个Java进程可以通过系统调用(mmap)或标准库(malloc)方法来向OS申请内存。malloc自己又通过mmap来向OS申请比较大的内存,并通过自己的算法来管理这些内存,这可能会导致内存碎片,从而导致过量使用虚拟内存。jemalloc是另外一个内存分配器,它比常规的malloc分配器需要更少的footprint,因此可以在自己的C 代码中尝试使用jemalloc方法。

结论

无法准确统计一个Java进程使用的虚拟内存,因为有太多因素需要考虑,列举如下:

1Total memory = Heap   Code Cache   Metaspace   Symbol tables
2               Other JVM structures   Thread stacks
3               Direct buffers   Mapped files
4               Native Libraries   Malloc overhead   ...

作者:CSDN博主「javaadu」,本文首发于作者CSDN博客https://blog.csdn.net/duqi_2009/article/details/101158407。

扫描下方二维码,下载 CSDN App,查看博主精彩分享

【END】

学Python想要达到大牛水准,你得这么学!

https://edu.csdn.net/topic/python115?utm_source=csdn_bw

CSDN 博客诚邀入驻啦!

本着共享、协作、开源、技术之路我们共同进步的准则,

只要你技术够干货,内容够扎实,分享够积极,

欢迎加入 CSDN 大家庭!

扫描下方二维码,即刻加入吧!

 热 文 推 荐 

Python 分析热门旅游景点,告诉你哪些地方好玩、便宜、人又少!
点击阅读原文,即刻阅读《程序员大本营》最新期刊。
你点的每个“在看”,我都认真当成了喜欢

为什么 Java 进程使用的 RAM 比 Heap Size 大?​ | CSDN博文精选相关推荐

  1. 为什么Java进程使用的RAM比Heap Size大?

    点击蓝色"程序猿DD"关注我 回复"资源"获取独家整理的学习资料! 作者 | 阿杜的世界 来源 | 公众号「javaadu」 Java进程使用的虚拟内存确实比J ...

  2. Java 9 ← 2017,2019 → Java 13 ,Java 两年来都经历了什么?| CSDN 博文精选

    作者 | Hollis 责编 | maozz 出品 | CSDN 博客 距离 2019 年结束,只剩下 35 天了.你做好准备迎接 2020 年了吗? 一到年底,人就特别容易陷入回忆和比较之中,比如说 ...

  3. 盘点 6 个被淘汰的 Java 技术,它们都曾经风光过!| CSDN 博文精选

    作者 | 栈长 责编 | 屠敏 出品 | CSDN 博客 今天给大家分享下我的开发历程中,我知道的那些被淘汰的技术或者框架,有些我甚至都没有用过,但我知道它曾经风光过. 废话不多说,下面我要开始吹了- ...

  4. java队列_如何彻底搞懂 Java 数据结构?CSDN 博文精选

    作者 | 张振华.Jack 责编 | 郭芮 出品 | CSDN 博客 本文和大家一起来重温<Java数据结构>经典之作. Java数据结构 要理解Java数据结构,必须能清楚何为数据结构? ...

  5. java 固定长度队列_如何彻底搞懂 Java 数据结构?|CSDN 博文精选

    作者 | 张振华.Jack 责编 | 郭芮 出品 | CSDN 博客 本文和大家一起来重温<Java数据结构>经典之作. Java数据结构 要理解Java数据结构,必须能清楚何为数据结构? ...

  6. 如何彻底搞懂 Java 数据结构?|CSDN 博文精选

    作者 | 张振华.Jack 责编 | 郭芮 出品 | CSDN 博客 本文和大家一起来重温<Java数据结构>经典之作. Java数据结构 要理解Java数据结构,必须能清楚何为数据结构? ...

  7. 为什么虚拟机上一运行就显示程序停止_五分钟学Java:如何学习Java面试必考的JVM虚拟机||CSDN博文精选...

    作者:黄小斜 原创声明 本文作者:黄小斜 转载请务必在文章开头注明出处和作者. 本文思维导图 为什么要学习JVM虚拟机 最近的你有没有参加Java面试呢?你有没有发现,Java面试中总是爱考一类问题, ...

  8. html 如何实现一条竖线边上有 刻度_记一次腾讯面试:进程之间究竟有哪些通信方式?如何通信? ---- 告别死记硬背||CSDN博文精选...

    作者:帅地 有一次面试的时候,被问到进程之间有哪些通信方式,不过由于之前没深入思考且整理过,说的并不好.想必大家也都知道进程有哪些通信方式,可是我猜很多人都是靠着"背"来记忆的,所 ...

  9. 春招妥了!资深技术面试官教你这样准备 Java 面试! | CSDN 博文精选

    作者 | hsm_computer 责编 | 伍杏玲 出品 | CSDN博客 Java能力和面试能力,这是两个方面的技能,可以这样说,如果不准备,一些大神或许也能通过面试,但能力和工资有可能被低估.再 ...

最新文章

  1. Ping一下Github,确认本地DNS无法解析方法
  2. 三方面搞定http协议之“状态码”
  3. java容器集合类的区别用法_Java容器笔记(二):不同集合实现类的特点与区别...
  4. 阿里巴巴右侧6滑块VS雅虎右侧6滑块VS自定义6滑块
  5. 屌丝逆袭,通过相亲实现阶层跃迁的秘诀
  6. HDU 5928 DP 凸包graham
  7. SQLite 插入大量数据慢的解决方法
  8. 华为路由器eNSP的基本配置
  9. 使用命令行查看Windows系统激活信息
  10. 计算机相关期刊,计算机相关杂志
  11. STM32F303RE 四个ADC同步规则采样
  12. 关于长高问题 我的看法
  13. r语言赋值为na_R语言中特殊值NaN、Inf 、NA、NULL
  14. w ndows10QQ远程,win10系统QQ远程协助无法操作对方电脑的解决办法
  15. Leetcode-前缀和
  16. 《半小时漫画中国哲学史》——读书笔记
  17. 逻辑移位和算术移位的区别
  18. 1_VBA_POWERSHELL病毒分析
  19. 进网许可证鸿蒙系统,疑似Galaxy S9 mini获得工信部入网许可 采用骁龙845 +6GB运存...
  20. python趣味题_从CSDN的趣味题学PYTHON

热门文章

  1. 来认识下less css
  2. [FFmpeg] RGBA 和 YUV 存储方式
  3. [Linux] 头文件加载顺序
  4. c语言基础知识难点,C语言基础的几个难点解析
  5. 【深度学习】深度学习入门——BP网络反向传播
  6. 矩池云上安装caffe gpu教程
  7. 使用 MobaXterm 连接矩池云 GPU服务器
  8. leetcode python3 简单题171. Excel Sheet Column Number
  9. Linux生成子进程函数fork()
  10. Flutter进阶—简单平台插件实例