java process consume more memory than Xmx
java应用程序启动时,我们常常会加上
-Xmx
选项,以确保进程不会吃掉我们限制的范围。然后你可能收到这样的惊喜。当打开命令行工具,查看
top
信息。会发现应用吃掉的内存[resident memory usage(RES)]超过了我们的预设。
为什么进程消耗的内存超过了我们分配?是bug还是完全正常的现象?
首先,一部分原因可能是代码造成的内存泄漏。但是,99%的情况下,都是jvm的正常行为。因为 -Xmx
仅仅是限制了应用程序的堆大小。
除了堆,这里还有其他几个内存空间被应用程序使用,比如 permgen
、stack
。为了限制它们,我们需要额外指定几个参数 -XX:MaxPermSize
、-Xss
。
简而言之,我们可以通过如下公式,预测我们应用的内存占用:
1 | Max memory = [-Xmx] + [-XX:MaxPermSize] + number_of_threads * [-Xss] |
但是,除应用外。jvm本身也要消耗内存:
- 垃圾收集
- java是一门自动垃圾回收语言,自动回收程序跟踪对象,执行回收需要占用内存
- G1更是出了名的倾向于过多占用内存
- 即时编译(JIT)
- 虚拟机为了提升代码执行效率
- 需要跟踪代码执行
- 堆外内存
- 使用直接或映射的 ByteBuffers 或者三方工具。在无意中拓展了堆空间,这些空间不被java虚拟机控制
- 本地接口(JNI)
- 使用本地代码,就要占用本地内存
- 元空间(Metaspace)
- java8中新增的空间,取代永久代保存类定义信息。