Java 进程中有哪些组件会占用内存?

Docker和JVM应用OOM那些事 Java 应用运行过程中你是否遇到以下类似问题为什么 Java 应用所在的 Docker 容器内存使用量不会减少?发生 OOM 后程序还能运行吗?Java 应用所在的容器为什么宕机或者自动重启了?三个问题有一定关联性,在回答以上问题前,我们先了解下“OOM”和“JVM 内存管理”。 阅读详情

楼主发现 Java 进程占用内存远超过堆内存设置的大小,于是提出了下面的问题:

有谁能解释为什么 Java 进程占用内存远超过堆内存大小?如何正确计算 Docker 内存限制?有没有办法减少 Java 进程的堆外内存(off-heap memeory)占用?

"下面是热心网友的答复"

Java 进程使用的虚拟内存远远超过 Java 堆大小。要知道 JVM 包括许多子系统,垃圾回收器、类装载器、JIT 编译器等等。所有这些子系统运行都需要占用内存。

JVM 不是内存唯一的消费者,Java Class Library 在内的所有 Native Library 也会占用内存。对于内存跟踪工具来说这些开销甚至无法跟踪。Java 应用程序本身还可以通过直接 ByteBuffers 使用堆外内存。

一、究竟 Java 进程中有哪些组件会占用内存?

通过 Native Memory Tracking 可以观察到有以下 JVM 组件。

1.1 Java 堆

最显而易见的就是 Java 堆,它是 Java 对象存在的地方。它会占用 -Xmx 参数指定大小的内存。

1.2 垃圾回收器

GC 需要额外的内存进行堆管理,主要用于 GC 自身的结构与算法。这些结构包括 Mark Bitmap、Mark Stack(遍历对象关系图)、Remembered Set(记录 region 之间引用)等等。其中一些可以直接调优,例如 -XX: MarkStackSizeMax 选项,另一些依赖于堆布局。其中 G1 region (-XX:G1HeapRegionSize)占用内存较大,Remembered Set 占用内存较小。

GC 的内存开销因算法而异,其中 -XX:+UseSerialGC 与 -XX:+UseShenandoahGC 的开销最小,而 G1 或 CMS 则会轻松占用大约10%的堆内存。

1.3 代码缓存
代码缓存包含动态生成的代码,JIT 编译生成的方法、解释器以及运行时 stub 代码。代码大小受 -XX:ReservedCodeCacheSize 选项限制(默认为240M)。关闭 -XX:-TieredCompilation 可以减少已编译代码的数量,从而减小代码缓存。

1.4 编译器

JIT 编译器本身工作时也需要内存。可以通过关闭 Tiered Compilation 或者 -XX:CICompilerCount 减少编译使用的线程数。

1.5 类加载

类的元数据存储在 Metaspace 堆外区域中,包括方法字节码、符号、常量池、注解等。加载的类越多,使用的元数据就越多。可以通过 -XX:MaxMetaspaceSize(默认无上限)和 -XX:CompressedClassSpaceSize(默认1G)选项控制元数据总大小。

1.6 符号表

JVM 有两个主要的 hashtable:符号表包含名称、签名、标识符等,String 表包含对 interned String 引用。如果 Native Memory Tracking 显示 String 表使用了大量内存,这可能意味着应用程序调用 String.intern 过于频繁。

1.7 线程

线程堆栈也会申请内存。堆栈大小由 -Xss 选项指定,默认每个线程1M,幸运的是情况并非那么糟糕。操作系统会以延迟分配的方式分配内存页面,比如在第一次使用时分配,因此实际使用的内存要低得多,通常每个线程堆栈占用80至200KB。

还有其他 JVM 部件会占用本地内存,但它们在总内存消耗中通常比例不大。

二、Direct Buffer

应用程序可以通过 ByteBuffer.allocateDirect 调用直接请求非堆内存。默认的非堆内存大小限制由 -Xmx 选项指定,但也可以使用 -XX:MaxDirectMemorySize 覆盖配置。Direct ByteBuffer 包含在 Native Memory Tracking 输出的 Other 区域,在 JDK 11 之前包含在 Internal 区域。

通过 JMX 可以在 JConsole 或 Java Mission Control 中直接看到 Direct Memory 的使用量:

除了 Direct ByteBuffer,还有 MappedByteBuffer 映射到进程虚拟内存中的文件。虽然 Native Memory Tracking 不对它跟踪,但是 MappedByteBuffer 也会占用物理内存,而且没有一种简单的方法限制它申请的内存大小。可以通过查看进程内存映射了解实际的内存使用情况:pmap-x。

shell
Address Kbytes RSS Dirty Mode Mapping
...
00007f2b3e557000 39592 32956 0 r--s- some-file-17405-Index.db
00007f2b40c01000 39600 33092 0 r--s- some-file-17404-Index.db
^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^

三、Native Library

System.Loadlibrary 加载的 JNI 代码可以不受 JVM 控制分配堆外内存,标准 Java Class Library 也是如此。尤其是未关闭的 Java 资源可能造成本地内存泄漏。典型的例子是 ZipInputStream 和 DirectoryStream。

JVMTI 代理,尤其是 jdwp 调试代理,也会造成内存消耗过多。

四、Allocator 问题

进程通常通过 mmap 系统调用直接从操作系统分配内存,或者使用标准的 libc allocator —— malloc 分配本机内存。反过来,malloc 会调用 mmap 向操作系统申请大块内存,然后根据自己的分配算法管理内存块。

五、总结

因为有太多的因素需要考虑,没有一种可靠的方法可以用来评估一个 Java 进程所有的内存使用量。

总内存 = 堆 + 代码缓存 + Metaspace + 符号表 +
其他 JVM 结构 + 线程堆栈 +
Direct Buffer + 映射文件 +
Native Library + Malloc 开销 + ...

虽然可以通过设置 JVM 参数缩小或限制类似代码缓存这样的区域,但是其他许多区域根本不受 JVM 控制。

设置 Docker 限制的一种可能的方法是观察进程“正常”状态下的实际内存使用情况。有一些工具和技术可以用来研究 Java 内存消耗问题

Process Explorer v15.12_Chs中文版:Java CPU使用率排查与优化 Process Explorer是一款由微软Sysinternals团队开发的系统监控工具,它的功能在IT领域内非常知名。它提供了一个更直观且功能丰富的界面,相较于Windows任务管理器,Process Explorer能够提供更深层次的进程和系统活动信息。这对于IT专业人员来说,是诊断系统问题、监控资源使用和优化系统性能不可或缺的工具。系统服务和Java资源的优化对于确保系统的稳定性和应用的性能至关重要。 阅读详情

相关推荐

代码实现ROS2bag录制数据和回放数据(C++)

ROS2的ROS2bag功能可以将指定Topic中的数据以.db3的格式(不同于ROS)保存到本地文件中。读取文件数据可以实现数据回放。

m0_57124501的博客 3257

Java项目内存知乎_Java应用程序是如何浪费内存的

内存是当今世界上被广泛浪费的硬件资源之一。由于编程效率低下,惊人量的内存浪费被浪费了。这种模式在多个企业应用程序中重复出现。为了证明这种情况,我们进行了一项小型研究。我们分析了著名的spring boot pet诊所应用程序,以查看浪费了多少内存。该应用程序是由spring社区设计的,旨在显示spring应用程序框架如何用于构建简单但功能强大的面向数据库的应用程序。环境准备Spring Boot ...

weixin_28730131的博客 432

Android BluetoothSocket

BluetoothSocket是Android中用于在蓝牙设备之间进行数据传输的一种Socket。它提供了一种类似于TCP/IP协议的数据传输方式,可以在两个设备之间建立一个虚拟的通信管道,使得两个设备之间可以进行数据的传输和接收。BluetoothSocket可以用于客户端和服务端之间的通信,通过BluetoothSocket可以实现数据的双向传输。

liuning1985622的博客 1478

JVM总结四

JVM参数配置 Java GC机制的目的是为了实用,也就是为了在JVM出现问题时分析原因并解决之,JVM监控与调优主要的着眼点在于如何配置、如何监控、如何优化3点上 java虚拟机的参数中,有3种表示方法 标准参数(-),所有的JVM实现都必须实现这些参数的功能,而且向后兼容; 非标准参数(-X),默认jvm实现这些参数的功能,但是并不保证所有jvm实现都满足,且不保证向后兼容; 非Stable参数(-XX),此类参数各个jvm实现会有所不同,将来可能会随时取消,需要慎重使用(但是,这些参数往往是非常有用

qq_52840805的博客 974

开发具有情感分析能力的AI Agent

本文将深入探讨开发具有情感分析能力的AI Agent的各个方面。我们将首先介绍情感分析的基础知识,包括定义、背景和应用领域。接着,我们将详细讲解情感分析的核心概念、数据处理方法和算法原理。随后,文章将展示如何设计情感分析系统架构,并进行项目实战,包括环境安装、源代码实现和案例分析。最后,我们将总结最佳实践和注意事项,为读者提供进一步学习的资源。情感分析(Sentiment Analysis),也称为意见挖掘,是自然语言处理(NLP)的一个分支。

SuperAGI2025 1146

【水文学法总结】河道内生态流量计算方法(含MATLAB实现代码)

简介水文学法实现河道内生态流量计算

WW、forever的博客 5020

java jvm 进程内存占用排查. 除了堆之外

java 内存可分为: 堆和meta space .查看堆: jmap -heap pid查看metaSpace: 使用 jstat -gc pid mc mu.查看进程内的其他占用: top 里的rs占用 减去 jmap -heap 里的占用. /proc/$PID/mapssmaps是更详细的信息 pamp pid :anon 的意思是内存分配. $cat...

fei33423的专栏 5858

ANSYS——“There is at least 1 small equation solver pivot term”问题的解决办法

ANSYS——“There is at least 1 small equation solver pivot term”问题的解决办法

python_AI_fans的博客 1万+

Java程序在Docker容器环境中的新挑战与解决方案

将Java应用程序迁移到Docker容器环境带来了许多优势,如快速部署、可移植性和资源隔离。然而,这也带来了一系列新的挑战,包括内存管理、资源隔离、镜像构建、网络配置、性能调优、持续集成与部署、监控与日志收集以及安全与合规性。通过了解这些挑战并采取相应的解决方案,开发人员和运维人员可以充分发挥容器技术的潜力,提高Java应用程序的可靠性、安全性和性能。

让每一行代码都有改变世界的力量 956

pi-coding-agent 完整详解

pi-coding-agent是一个由Mario Zechner开发的专业AI编程助手,基于Node.js和TypeScript构建。核心功能包括:1)多级思考模式(ThinkingLevel),从none到ultra控制推理深度;2)对话压缩(compaction)管理长对话记忆;3)WebSocket实时通信支持流式交互。该智能体支持代码生成、调试、重构等专业编程任务,采用AI Agent架构,具备工具调用和多轮记忆能力。项目结构通常包含server、agent、config等模块,可通过二次开发扩展功

大坡3D软件开发 2442

视觉SLAM十四讲slambook2示例代码所有依赖库的编译安装教程(VTK、OpenCV3、ceres、Sophus、g2o、Eigen、Pangolin、googletest等)

这是2021年的最后一篇博客~ 新年快乐! 0 准备工作   首先需要先安装cmake编译器: sudo apt-get install cmake   以及,将十四讲的示例代码克隆下来(十四讲的源码地址点击这里): git clone --recursive https://github.com/gaoxiang12/slambook2.git   由于里面的3rdparty文件夹内所有内容都来自于其他github仓库,所以需要加上--recursive参数,不然克隆下来的内容不完整。   如果你.

zeeq的博客 7839

内存占用_Java 进程中有哪些组件会占用内存?

(给ImportNew加星标,提高Java技能)编译:唐尤华本文来自 StackOverflow 的一个问答:Java using much more memory than heap size (or size correctly Docker memory limit) 题主发现 Java 进程占用内存远超过堆内存设置的大小,于是提出了下面的问题:有谁能解释为什么 Java 进程占...

weixin_39955421的博客 260

【ARM CoreLink 系列 5.3 -- CI-700 SLC memory 系统组件详细介绍】

在 CI-700 系统级缓存(SLC)内存系统中,HN-F 节点负责管理缓存一致性和数据传输。每个 HN-F 节点可以发送三种类型的 Snoop 请求,以确保系统中多核处理器和缓存之间的一致性。CI-700 中的系统级缓存(SLC)内存系统通过 HN-F 节点支持 TrustZone® 技术。以下是 CI-700 支持的 SN 类型以及配置方法的简要介绍。ARM CI-700 系统级缓存(SLC)是一个分布式、主要排他性(mostly exclusive) 的最后一级缓存,集成在 HN-F 节点内。

CodingCos的博客 898

was进程内存占用过大_Java 进程中有哪些组件会占用内存?

楼主发现 Java 进程占用内存远超过堆内存设置的大小,于是提出了下面的问题:有谁能解释为什么 Java 进程占用内存远超过堆内存大小?如何正确计算 Docker 内存限制?有没有办法减少 Java 进程的堆外内存(off-heap memeory)占用?"下面是热心网友的答复"Java 进程使用的虚拟内存远远超过 Java 堆大小。要知道 JVM 包括许多子系统,垃圾回收器、类装载器、JIT 编...

weixin_29040367的博客 226

IDEA的使用指南

IDEA基于java的使用手册,可以最快速的上手,在使用中不断的丰富自己的使用技巧.

老版QQ原生表情gif动态

这是老版的QQ表情,不过全是动态的的,Windows照片查看器是不会动的,可以右击用浏览器打开查看,再说一遍是老版的,只是分享给宁愿用老版也要动态的人。

docker 设置 jvm 内存_Java 进程中有哪些组件会占用内存?

楼主发现 Java 进程占用内存远超过堆内存设置的大小,于是提出了下面的问题:有谁能解释为什么 Java 进程占用内存远超过堆内存大小?如何正确计算 Docker 内存限制?有没有办法减少 Java 进程的堆外内存(off-heap memeory)占用?"下面是热心网友的答复"Java 进程使用的虚拟内存远远超过 Java 堆大小。要知道 JVM 包括许多子系统,垃圾回收器、类装载器、JIT 编...

weixin_39662228的博客 175

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

inputstream 占用内存吗_Java 进程中有哪些组件会占用内存?

本文来自 StackOverflow 的一个问答:Java using much more memory than heap size (or size correctly Docker memory limit)题主发现Java 进程占用内存远超过堆内存设置的大小,于是提出了下面的问题:有谁能解释为什么 Java 进程占用内存远超过堆内存大小?如何正确计算 Docker 内存限制?有没有办法减少...

weixin_36382534的博客 451

VB摄像头监控

该VB模块可对摄像头捕获的画面进行录像等,可在创建的窗口进行控制

面试官上来就问:Java 进程中有哪些组件会占用内存?

本文的内容来自 StackOverflow 的一个问答:Java using much more memory than heap size (or size correctly Docker memory limit) 有网友留言,今天去参加面试,面试官上来就问:你能解释为什么 Java 进程占用内存远超过堆内存大小?如何正确计算 Docker 内存限制?有没有办法减少 Java 进程的堆...

勇往直前的专栏 620

oracle内存最小分配多少_Java 进程中有哪些组件会占用内存?

(给ImportNew加星标,提高Java技能)编译:唐尤华本文来自 StackOverflow 的一个问答:Java using much more memory than heap size (or size correctly Docker memory limit) 题主发现 Java 进程占用内存远超过堆内存设置的大小,于是提出了下面的问题:有谁能解释为什么 Java 进程占...

weixin_39803207的博客 113

Java内存之本地内存分析神器: NMT 和 pmap

其他团队的一些同事经常问我一个问题:你的Java进程怎么占了那么多Virtual Size和RSS? 最近,我基本上可以回答清楚这个问题了。用NMT和pmap基本就就能搞清楚Java进程为什么占了那些Virtual Size和RSS。 NMT是Native Memory Tracking的缩写,是Java7U40引入的HotSpot新特性。 pmap,众所周知,就是Linux上用了看进程地址空间

jicahoo的专栏 2万+

一次java应用内存占用分析

发现展示的内存占用更多了,总占用的335M和第二步中的360M已经很接近,而第三步的157M约等于java heap和class之和,除此之外主要还包含thread的内存,上图中#143表示线程数,默认一个线程1M(图中的线程占用被修改成了228K)(2)执行jcmd 24417 VM.native_memory scale=MB。得到进程pid是24417,同时能看到设置的最大堆内存是100M。可以算出整个java进程大约占用360M,发现一个问题,(1)top(可按shift+M按内存排序)

liujevon1212的博客 998

Java微服务内存占用分析

一、Java 进程中有哪些组件会占用内存? 通过 Native Memory Tracking 可以观察到有以下 JVM 组件。在命令行加上-XX:NativeMemoryTracking=summary,会增加3MB左右内存,损失5%-10%CPU,不宜用于生产环境。 使用 jcmd <pid> VM.native_memory summary scale=MB 可以查看内存分配...

lgxzzz的博客 7292

为什么Java进程使用的内存(RSS)比Heap Size大?

Java进程使用的虚拟内存确实比Java Heap要大很多。JVM包括很多子系统:垃圾收集器、类加载系统、JIT编译器等等,这些子系统各自都需要一定数量的RAM才能正常工作。 当一个Java进程运行时,也不仅仅是JVM在消耗RAM,很多本地库(Java类库中引用的本地库)可能需要分配原生内存,这些内存无法被JVM的Native Memory Tracking机制监控到。Java应用自身也可能通过DirectByteBuffers等类来使用堆外内存。 那么,当一个Java进程运行时,有哪些部分在消耗内存呢

flyingnet的博客 4798

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

Java进程使用的虚拟内存确实比Java Heap要大很多。JVM包括很多子系统:垃圾收集器、类加载系统、JIT编译器等等,这些子系统各自都需要一定数量的RAM才能正常工作。 当一个Java进程运行时,也不仅仅是JVM在消耗RAM,很多本地库(Java类库中引用的本地库)可能需要分配原生内存,这些内存无法被JVM的Native Memory Tracking机制监控到。Java应用自身也...

weixin_30267691的博客 225

java为什么内存会无限增大_为什么javaw.exe占用的内存持续增加,一直不释放

你的Table DefaultTreeCellRenderer 图片渲染器定义的应该有问题.,因为默认的渲染器就是继承Jlable的,就不要继续new Jlabel,直接设置setIcon();就行. 给个TableCellRenderer 代码你参考下把1.创建table:TableColumnModel columnModel = table.getColumnModel();StatusT...

weixin_42314680的博客 972

使用MAT进行内存问题定位

MAT简介

有问题的请私信或关注v【技术印记】留言 1422
上一篇: 可提高Java开发性能的5款调试工具
下一篇: 不同行业的软件都爱用什么编程语言开发?
Java_No2
博客等级 码龄7年 20粉丝 109原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值