JVM 进程如何分配其内存?

     2023-02-25     99

关键词:

【中文标题】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 使用的不同内存区域的详细概述,并且还显示了 reservedcommited 内存。

我不知道有什么技术可以为您提供更详细的内存消耗列表。

进一步阅读:

您还可以将-XX:NativeMemoryTracking=detail 与更多jcmd 命令结合使用。更详细的解释可以在Java Platform, Standard Edition Troubleshooting Guide - 2.6 The jcmd Utility 找到。您可以通过"jcmd &lt;pid&gt; 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/... 查看详情