关键词:
【中文标题】JVM 进程如何分配其内存?【英文标题】:How does a JVM process allocate its memory? 【发布时间】:2016-05-31 20:26:23 【问题描述】:我在理解 JVM 进程如何分配自己的内存方面存在一些差距。据我所知
RSS = Heap size + MetaSpace + OffHeap size
其中 OffHeap 由线程堆栈、直接缓冲区、映射文件(库和 jar)和 JVM 代码本身组成;
目前我正在尝试分析我的 Java 应用程序(Spring Boot + Infinispan),其 RSS 为 779M(它在 docker 容器中运行,因此 pid 1 可以):
[ root@daf5a5ae9bb7:/data ]$ ps -o rss,vsz,sz 1
RSS VSZ SZ
798324 6242160 1560540
根据jvisualvm
,committed Heap size是374M
元空间大小为 89M
也就是说,我想说明799M - (374M + 89M) = 316M的OffHeap内存。
我的应用有(平均)36 个活动线程。
每个线程消耗1M:
[ root@fac6d0dfbbb4:/data ]$ java -XX:+PrintFlagsFinal -version |grep ThreadStackSize
intx CompilerThreadStackSize = 0
intx ThreadStackSize = 1024
intx VMThreadStackSize = 1024
所以,我们可以在这里添加 36M。
应用使用 DirectBuffer 的唯一地方是 NIO。据我从 JMX 可以看出,它并没有消耗很多资源——只有 98K
最后一步是映射库和罐子。但是根据pmap
(full output)
[ root@daf5a5ae9bb7:/data ]$ pmap -x 1 | grep ".so.*" | awk ' sum+=$3 END print sum'
12896K
加
root@daf5a5ae9bb7:/data ]$ pmap -x 1 | grep “.jar" | awk ' sum+=$3 END print sum'
9720K
我们这里只有 20M。
因此,我们还是要解释一下316M - (36M + 20M) = 260M :(
有人知道我错过了什么吗?
【问题讨论】:
JVM本身的所有共享库都有。尝试运行两个 JVM,看看增加了多少。 为出色的研究+1! 100% 同意@PeterLawrey。通过执行ldd /path/to/java' and 'pmap PID
来检查 Java 正在运行哪些共享库,以详细了解 Java 到底使用了什么。
另外,正如你所看到的,“used”比实际的堆大小要小得多。 VM 喜欢占用大量内存来提高 GC 性能。即使是使用过的堆,也有很多可能是死对象,在执行完整 GC 时会被回收。
+ CodeCache(用于动态生成的代码)+ GC 内部结构(如 CardTables)+ 本地库分配的结构(I/O、网络等)+ JVM 和库的 .bss 段
【参考方案1】:
方法:
您可能想使用Java HotSpot Native Memory Tracking (NMT)。
这可能会为您提供 JVM 分配的内存的准确列表,分为不同的区域 堆、类、线程、代码、GC、编译器、内部、符号、内存跟踪、池化空闲块、 和 未知。
用法:
您可以使用-XX:NativeMemoryTracking=summary
启动您的应用程序。
可以使用jcmd <pid> VM.native_memory summary
观察当前堆。
在哪里可以找到 jcmd/pid:
在 Ubuntu 上的默认 OpedJDK 安装中,可以在 /usr/bin/jcmd
找到。
通过不带任何参数运行jcmd
,您可以获得正在运行的Java 应用程序的列表。
user@pc:~$ /usr/bin/jcmd
5169 Main <-- 5169 is the pid
输出:
然后,您将收到堆的完整概览,如下所示:
总计: reserved=664192KB,committed=253120KB
Java 堆(保留=516096KB,提交=204800KB)
(mmap:保留=516096KB,提交=204800KB)
类(保留=6568KB,提交=4140KB)
(classes #665)
(malloc=424KB, #1000)
(mmap:保留=6144KB,提交=3716KB)
线程(保留=6868KB,提交=6868KB) (线程 #15)
(stack: reserved=6780KB, committed=6780KB)
(malloc=27KB, #66)
(arena=61KB, #30)
代码(保留=102414KB,提交=6314KB)
(malloc=2574KB, #74316)
(mmap:保留=99840KB,提交=3740KB)
GC(保留=26154KB,提交=24938KB)
(malloc=486KB, #110)
(mmap:保留=25668KB,提交=24452KB)
编译器(保留=106KB,提交=106KB)
(malloc=7KB, #90)
(竞技场=99KB,#3)
内部(保留=586KB,提交=554KB)
(malloc=554KB, #1677)
(mmap:保留=32KB,提交=0KB)
符号(保留=906KB,提交=906KB)
(malloc=514KB, #2736)
(竞技场=392KB,#1)
内存跟踪(保留=3184KB,提交=3184KB)
(malloc=3184KB, #300)
池化的空闲块(保留=1276KB,提交=1276KB)
(malloc=1276KB)
未知(保留=33KB,提交=33KB)
(竞技场=33KB,#1)
这给出了 JVM 使用的不同内存区域的详细概述,并且还显示了 reserved 和 commited 内存。
我不知道有什么技术可以为您提供更详细的内存消耗列表。
进一步阅读:
您还可以将-XX:NativeMemoryTracking=detail
与更多jcmd
命令结合使用。更详细的解释可以在Java Platform, Standard Edition Troubleshooting Guide - 2.6 The jcmd Utility 找到。您可以通过"jcmd <pid> help"
查看可能的命令
【讨论】:
您在jcmp
中有错字?
谢谢,稍后会解决这个问题。
感谢您的回答!我尝试使用 NMT 并发现它非常有帮助......但我仍然有一个问题 :) NMT 说我丢失的所有内存都属于“Unkonwn”部分。当我尝试分析详细信息时,我发现以下内容:gist.github.com/krestjaninoff/a89ee990d94d8fc2917a您对这段记忆发生了什么有任何想法?它被 CMS 消耗了吗?
“此版本中的 NMT 不跟踪第三方本机代码内存分配和 JDK 类库。” (c) 好的,问题结束了:)
jvm-内存分配与回收策略
...文进行了总结,那么接下来主要就是谈谈自己对JVM是如何给对象分配内存这一部分的理解。JVM的内存空间是有限的,并且堆内存是共享的,那么不同线程共用堆内存如何保证线程安全都是需要考虑的问题。 通过之... 查看详情
《深入理解java虚拟机》--内存
...一种应用程序,JVM要运行的时候,操作系统会创建对应的进程而且分配一定大小的内存。 一、内存结构 当虚拟机得到系统分配的内存后,它在其内存空间中就是老大,管理对象内存的分配以及对象内存的回收,同时可以... 查看详情
jvm内存分区(代码片段)
...通过字节码解释器加载运行。那么程序开始运行后,都是如何涉及到各内存区域的呢?概括地说来,JVM初始运行的时候都会分配好MethodArea(方法区)和Heap(堆),而JVM每遇到一个线程,就为其分配一个ProgramCounterRegiste 查看详情
jvm-内存分配与回收策略
...篇博文进行了总结,那么接下来主要就是谈谈自己对JVM是如何给对象分配内存这一部分的理解。JVM的内存空间是有限的,并且堆内存是共享的,那么不同线程共用堆内存如何保证线程安全都是需要考虑的问题。 &nbs 查看详情
jvm-内存分配与回收策略
...文进行了总结,那么接下来主要就是谈谈自己对JVM是如何给对象分配内存这一部分的理解。JVM的内存空间是有限的,并且堆内存是共享的,那么不同线程共用堆内存如何保证线程安全都是需要考虑的问题 查看详情
jvm-直接内存
NIO,使用native函数库直接分配堆外内存,不经过JVM内存直接访问系统物理内存的类——DirectBuffer。DirectBuffer类继承自ByteBuffer,但和普通的ByteBuffer不同,普通的ByteBuffer仍在JVM堆上分配内存,其最大内存受到最大堆内... 查看详情
java内存模型
...avaMemoryModel,简称JMM,其规范了Java虚拟机与计算机内存时如何协同工作的,规定了一个线程如何和何时看到其他线程修改过的值,以及在必须时,如何同步访问共享变量。 2.JVM的内存分配在解释Java内存模型之前... 查看详情
jvm深入理解自动内存分配与垃圾回收
...自动内存分配,首先必须了解jvm的运行时数据区域,否则如何知道在哪里进行自动内存分配,如何进行内存分配,回收哪里的垃圾对象?jvm运行时数据区:程序计数器,虚拟机栈,本地方法栈,方法区,堆程序计数器:由于程序... 查看详情
jvm之内存分配与回收策略
前言 对象的内存分配,往大的方向上讲,就是在堆上分配,少数情况下也可能会直接分配在老年代中,分配的规则并不是百分之百固定的,其细节决定于当前使用的是哪种垃圾收集器组合,当然还有虚拟机中与内存... 查看详情
jvm:7对象在jvm内存中如何分配与流转?
1.两种对象代码里创建出来的对象,一般有如下两种:一种是短期存活的,分配在Java堆内存之后,迅速使用完就会被垃圾回收;另外一种是长期存活的,需要一直生存在Java堆内存里,让程序后续不停的... 查看详情
当使用java命令运行.class文件的时候,就相当于启动了一个jvm进程,如何理解?
请教各位大佬,这里说的启动了一个JVM进程,这个进程和操作系统进程是一个意思么?我不太理解jvm当中具体有哪些进程,望解答。谢谢。进程是操作系统资源管理的基本单位,运行.class文件和打开一个应用软件(当然有些软件可... 查看详情
java进程内存泄漏判断及解决方法
内存泄漏种类Java使用的内存种类包含三种,这三种类型的内存都可能发生内存泄漏。?堆内存泄漏,如果JVM不能在java堆中获得更多内存来分配更多java对象,将会抛出java堆内存不足(javaOOM)错误。如果java堆充满了活动对象,并且JVM... 查看详情
os内核参数和jvm参数的调整
...0,1,20:表示内核将检查是否有足够的可用内存供应用进程使用;如果有足够的可用内存,内存申请允许;否则,内存申请失败,并把错误返回给应用进程。1:表示内核允许分配所有的物理内存,而不管当前的内存状态如何。2... 查看详情
限制容器的内存使用量与限制容器内jvm进程的内存使用量?哪个更好?(代码片段)
我有一个容器,我在其中运行6个进程。还有3个其他容器在做同样的事情。如果分配给该组的大小为30GB,我发现几乎整个RAM都在填充,即使物理内存只需要25GB。所以我决定限制。我应该限制什么?我应该将每个容器限制为每个8G... 查看详情
jvm系列jvm垃圾收集器与内存分配策略
...完成三件事情:哪些内存需要回收?什么时候进行回收?如何回收?本篇博客将解答jvm是如何处理以上三个问题的。值得注意的是,java运行时数据区中的程序计数器,虚拟机栈,本地方法栈三个区域随线程而生,随线程而灭,... 查看详情
java程序运行时内存分配详解(代码片段)
...解 一、 基本概念 每运行一个java程序会产生一个java进程,每个java进程可能包含一个或者多个线程,每一个Java进程对应唯一一个JVM实例,每一个JVM实例唯一对应一个堆 查看详情
jvm内存分配与回收
...是否被持有引用的呢?下面我们将一一来进行分析。 如何判断对象 查看详情
深入理解jvm之jvm内存区域与内存分配
深入理解JVM之JVM内存区域与内存分配 在学习jvm的内存分配的时候,看到的这篇博客,该博客对jvm的内存分配总结的很好,同时也利用jvm的内存模型解释了java程序中有关参数传递的问题。 博客出处: http://www.cnblogs.com/... 查看详情