JVM 与 Linux 的内存关系详解

高效数据迁移:ICCAP到ADS的数据导入与导出实战指南 本文提供了从ICCAP到ADS进行高效、准确数据迁移的实战指南。针对射频与微波电路设计中的关键挑战,详细阐述了迁移前的战略规划、ICCAP数据的精细化导出(包括脚本化批处理)、ADS数据的多种导入方法(如Data Items、DML模型库及编程化API),并强调了数据完整性与准确性验证的重要性,确保模型参数和仿真结果在平台间可靠传递。 阅读详情

JVM 与 Linux 的内存关系详解

在一些物理内存为8g的服务器上,主要运行一个Java服务,系统内存分配如下:Java服务的JVM堆大小设置为6g,一个监控进程占用大约 600m,Linux自身使用大约800m。

从表面上,物理内存应该是足够使用的;但实际运行的情况是,会发生大量使用SWAP(说明物理内存不够使用 了),如下图所示。由于SWAP和GC同时发生会致使JVM严重卡顿,所以我们要追问:内存究竟去哪儿了?

JVM 与 Linux 的内存关系详解

JVM 与 Linux 的内存关系详解

要分析这个问题,理解JVM和操作系统之间的内存关系非常重要。接下来主要就Linux与JVM之间的内存关系进行一些分析。

一、Linux与进程内存模型


JVM以一个进程(Process)的身份运行在Linux系统上,了解Linux与进程的内存关系,是理解JVM与Linux内存的关系的基础。下图给出了硬件、系统、进程三个层面的内存之间的概要关系。

JVM 与 Linux 的内存关系详解

从硬件上看,Linux系统的内存空间由两个部分构成:物理内存和SWAP(位于磁盘)。物理内存是Linux活动时使用的主要内存区域;当物理内存不够使用时,Linux会把一部分暂时不用的内存数据放到磁盘上的SWAP中去,以便腾出更多的可用内存空间;而当需要使用位于SWAP的数据时,必须 先将其换回到内存中。JVM运行时区域详解,推荐大家看下。

从Linux系统上看,除了引导系统的BIN区,整个内存空间主要被分成两个部分:内核内存(Kernel space)、用户内存(User space)。

内核内存是Linux自身使用的内存空间,主要提供给程序调度、内存分配、连接硬件资源等程序逻辑使用。

用户内存是提供给各个进程主要空间,Linux给各个进程提供相同的虚拟内存空间;这使得进程之间相互独立,互不干扰。实现的方法是采用虚拟内存技术:给每一个进程一定虚拟内存空间,而只有当虚拟内存实 际被使用时,才分配物理内存。

如下图所示,对于32的Linux系统来说,一般将0~3G的虚拟内存空间分配做为用户空间,将3~4G的虚拟内存空间分配 为内核空间;64位系统的划分情况是类似的。

JVM 与 Linux 的内存关系详解

从进程的角度来看,进程能直接访问的用户内存(虚拟内存空间)被划分为5个部分:代码区、数据区、堆区、栈区、未使用区。

代码区中存放应用程序的机器代码,运行过程中代码不能被修改,具有只读和固定大小的特点。

数据区中存放了应用程序中的全局数据,静态数据和一些常量字符串等,其大小也是固定的。

堆是运行时程序动态申请的空间,属于程序运行时直接申请、释放的内存资源。

栈区用来存放函数的传入参数、临时变量,以及返回地址等数据。

未使用区是分配新内 存空间的预备区域。

二、进程与JVM内存空间


JVM本质就是一个进程,因此其内存空间(也称之为运行时数据区,注意与JMM的区别)也有进程的一般特点。深入浅出 Java 中 JVM 内存管理,这篇参考下。

但是,JVM又不是一个普通的进程,其在内存空间上有许多崭新的特点,主要原因有两 个:

  • JVM将许多本来属于操作系统管理范畴的东西,移植到了JVM内部,目的在于减少系统调用的次数;
  • Java NIO,目的在于减少用于读写IO的系统调用的开销。JVM进程与普通进程内存模型比较如下图:

JVM 与 Linux 的内存关系详解

需要说明的是,这个模型的并不是JVM内存使用的精确模型,更侧重于从操作系统的角度而省略了一些JVM的内部细节(尽管也很重要)。下面从用户内存和内核内存两个方面讲解JVM进程的内存特点。

1.用户内存

上图特别强调了JVM进程模型的代码区和数据区指的是JVM自身的,而非Java程序的。普通进程栈区,在JVM一般仅仅用做线程栈。JVM的堆区和普通进程的差别是最大的,下面具体详细说明:

首先是永久代。永久代本质上是Java程序的代码区和数据区。Java程序中类(class),会被加载到整个区域的不同数据结构中去,包括常量池、域、方法数据、方法体、构造函数、以及类中的专用方法、实例初始化、接口初始化等。这个区域对于操作系统来说,是堆的一个部分;而对于Java程序来 说,这是容纳程序本身及静态资源的空间,使得JVM能够解释执行Java程序。

其次是新生代和老年代。新生代和老年代才是Java程序真正使用的堆空间,主要用于内存对象的存储;但是其管理方式和普通进程有本质的区别。

普通进程在运行时给内存对象分配空间时,比如C++执行new操作时,会触发一次分配内存空间的系统调用,由操作系统的线程根据对象的大小分配好空间后返 回;同时,程序释放对象时,比如C++执行delete操作时,也会触发一次系统调用,通知操作系统对象所占用的空间已经可以回收。

JVM对内存的使用和一般进程不同。JVM向操作系统申请一整段内存区域(具体大小可以在JVM参数调节)作为Java程序的堆(分为新生代和老年代);当Java程序申请内存空间,比如执行new操作,JVM将在这段空间中按所需大小分配给Java程序,并且Java程序不负责通知JVM何时可以释放这 个对象的空间,垃圾对象内存空间的回收由JVM进行。

JVM的内存管理方式的优点是显而易见的,包括:第一,减少系统调用的次数,JVM在给Java程序分配内存空间时不需要操作系统干预,仅仅在 Java堆大小变化时需要向操作系统申请内存或通知回收,而普通程序每次内存空间的分配回收都需要系统调用参与;第二,减少内存泄漏,普通程序没有(或者 没有及时)通知操作系统内存空间的释放是内存泄漏的重要原因之一,而由JVM统一管理,可以避免程序员带来的内存泄漏问题。

最后是未使用区,未使用区是分配新内存空间的预备区域。对于普通进程来说,这个区域被可用于堆和栈空间的申请及释放,每次堆内存分配都会使用这个区 域,因此大小变动频繁;对于JVM进程来说,调整堆大小及线程栈时会使用该区域,而堆大小一般较少调整,因此大小相对稳定。操作系统会动态调整这个区域的 大小,并且这个区域通常并没有被分配实际的物理内存,只是允许进程在这个区域申请堆或栈空间。

2.内核内存

应用程序通常不直接和内核内存打交道,内核内存由操作系统进行管理和使用;不过随着Linux对性能的关注及改进,一些新的特性使得应用程序可以使 用内核内存,或者是映射到内核空间。Java NIO正是在这种背景下诞生的,其充分利用了Linux系统的新特性,提升了Java程序的IO性能。

JVM 与 Linux 的内存关系详解

上图给出了Java NIO使用的内核内存在linux系统中的分布情况。nio buffer主要包括:nio使用各种channel时所使用的ByteBuffer、Java程序主动使用 ByteBuffer.allocateDirector申请分配的Buffer。

而在PageCache里面,nio使用的内存主要包 括:FileChannel.map方式打开文件占用mapped、FileChannel.transferTo和 FileChannel.transferFrom所需要的Cache(图中标示 nio file)。

通过JMX可以监控到NIO Buffer和 mapped 的使用情况,如下图所示。不过,FileChannel的实现是通过系统调用使用原生的PageCache,过程对于Java是透明的,无法监控到这部分内存的使用大小。

JVM 与 Linux 的内存关系详解

Linux和Java NIO在内核内存上开辟空间给程序使用,主要是减少不要的复制,以减少IO操作系统调用的开销。例如,将磁盘文件的数据发送网卡,使用普通方法和NIO时,数据流动比较下图所示:

JVM 与 Linux 的内存关系详解

将数据在内核内存和用户内存之间拷贝是比较消耗资源和时间的事情,而从上图我们可以看到,通过NIO的方式减少了2次内核内存和用户内存之间的数据拷贝。这是Java NIO高性能的重要机制之一(另一个是异步非阻塞)。

从上面可以看出,内核内存对于Java程序性能也非常重要,因此,在划分系统内存使用时候,一定要给内核留出一定可用空间。

三、案例分析


1.内存分配问题

通过上面的分析,省略比较小的区域,可以总结JVM占用的内存:
JVM内存 ≈ Java永久代 + Java堆(新生代和老年代) + 线程栈+ Java NIO

回到文章开头提出的问题,原来的内存分配是:6g(java堆) + 600m(监控) + 800m(系统),剩余大约600m内存未分配。

现在分析这600m内存的分配情况:

  • Linux保留大约200m,这部分是Linux正常运行的需要,
  • Java服务的线程数量是160个,JVM默认的线程栈大小是1m,因此使用160m内存,
  • Java NIO buffer,通过JMX查到最多占用了200m,
  • Java服务使用NIO大量读写文件,需要使用PageCache,正如前面分析,这个暂时不好定量估算大小。

前三项加起来已经560m,因此可以断定Linux物理内存不够使用。

细心的人会发现,引言中给出两个服务器,一个SWAP最多占用了2.16g,另外一个SWAP最多占用了871m;但是,似乎我们的内存缺口没有那么大。事实上,这是由于SWAP和GC同时进行造成的,从下图可以看到,SWAP的使用和长时间的GC在同一时刻发生。

JVM 与 Linux 的内存关系详解

JVM 与 Linux 的内存关系详解

SWAP和GC同时发生会导致GC时间很长,JVM严重卡顿,极端的情况下会导致服务崩溃。原因如下:JVM进行GC时,时需要对相应堆分区的已用 内存进行遍历;假如GC的时候,有堆的一部分内容被交换到SWAP中,遍历到这部分的时候就需要将其交换回内存,同时由于内存空间不足,就需要把内存中堆 的另外一部分换到SWAP中去;于是在遍历堆分区的过程中,(极端情况下)会把整个堆分区轮流往SWAP写一遍。Linux对SWAP的回收是滞后的,我 们就会看到大量SWAP占用。上述问题,可以通过减少堆大小,或者增加物理内存解决。

因此,我们得出一个结论:部署Java服务的Linux系统,在内存分配上,需要避免SWAP的使用;具体如何分配需要综合考虑不同场景下JVM对Java永久代 、Java堆(新生代和老年代)、线程栈、Java NIO所使用内存的需求。

2.内存泄漏问题

另一个案例是,8g内存的服务器,Linux使用800m,监控进程使用600m,堆大小设置4g;系统可用内存有2.5g左右,但是也发生了大量的SWAP占用。

分析这个问题如下:

  • 在这个场景中, Java永久代 、Java堆(新生代和老年代)、线程栈所用内存基本是固定的,因此,占用内存过多的原因就定位在Java NIO上。

  • 根据前面的模型,Java NIO使用的内存主要分布在Linux内核内存的System区和PageCache区。查看监控的记录,如下图,我们可以看到发生SWAP之前,也就是 物理内存不够使用的时候,PageCache急剧缩小。因此,可以定位在System区的Java NIO Buffer发生内存泄漏。

JVM 与 Linux 的内存关系详解

JVM 与 Linux 的内存关系详解

  • 由于NIO的DirectByteBuffer需要在GC的后期被回收,因此连续申请DirectByteBuffer的程序,通常需要调用 System.gc(),避免长时间不发生FullGC导致引用在old区的DirectByteBuffer内存泄漏。分析到此,可以推断有两种可能的 原因:第一,Java程序没有在必要的时候调用System.gc();第二,System.gc()被禁用。

  • 最后是要排查JVM启动参数和Java程序的DirectByteBuffer使用情况。在本例中,查看JVM启动参数,发现启用了-XX:+DisableExplicitGC导致System.gc()被禁用。

四、总结


本文详细分析了Linux与JVM的内存关系,比较了一般进程与JVM进程使用内存的异同点,理解这些特性将对Linux系统内存分配、JVM调优、Java程序优化有帮助。限于篇幅关系仅仅列举两个案例,希望起到抛砖引玉的作用。

AutoJs调用DeepSeek大模型接口实战教程 AutoJs接入DeepSeek、 DeepSeek API调用 、 手机脚本接入大模型 通过这篇文章,我们用 AutoJs 成功接入了 DeepSeek Chat API。使用发送请求在 Header 里正确携带 API Key从里拿到最终返回结果这样一来,你就可以在 AutoJs 里实现一个智能助手脚本,甚至做更复杂的 AI 自动化工具。 阅读详情

相关推荐

MATPOWER下载安装教程

将MATPOWER文件复制在C:\Program Files (x86)\MATLAB\R2016b\bin目录下。原来的窗口中多了很多文件路径,点击【保存】,再点击【关闭】选择所要添加的MATPOWER文件夹,点击【选择文件夹】二、将MATPOWER放在bin目录下。找到菜单栏的【设置路径】点击【添加并包含子文件】一、从官网下载后解压。

weixin_47365903的博客 2万+

JVM内存管理

1 物理内存与虚拟内存 物理内存就是RAM(随机存储器),还有一个存储单元叫做寄存器,连接处理器和RAM或者寄存器的是地址总线,这个地址总线的宽度影响了物理地址的索引范围,同时也决定了处理器最大可以寻址的地址空间。 除了硬件程序或者驱动程序需要直接访问存储器外,大部分情况下都是通过操作系统提供的接口来访问内存,在java中甚至不需要写和内存相关的代码。 我们要运行程序,都要向操作系统先申请内存地址,每个进程拥有一段独立的地址空间,操作系统也会保证每个进程只能访问自己的内存空间。 虚拟内存的出现使得多个进程

weixin_43877332的博客 846

深入解析SGLang框架:从架构设计到核心组件实现

本文深入解析了SGLang框架的架构设计与核心组件实现。SGLang是一个专为大语言模型推理设计的高效框架,其核心优势在于清晰的分层架构、高效的调度策略以及精细的内存管理。文章详细剖析了其客户端接入、服务器端调度、模型执行引擎及Tokenizer/Detokenizer管理器等关键组件,揭示了其实现高性能推理的内部机制。

coffee的博客 577

Linux与JVM的内存关系分析

引言 在一些物理内存为8g的服务器上,主要运行一个Java服务,系统内存分配如下:Java服务的JVM堆大小设置为6g,一个监控进程占用大约 600m,Linux自身使用大约800m。从表面上,物理内存应该是足够使用的;但实际运行的情况是,会发生大量使用SWAP(说明物理内存不够使用 了),如下图所示。同时,由于SWAP和GC同时发生会致使JVM严重卡顿,所以我们要追问:内存究竟去哪儿了?

张伟的专栏 975

SystemUI-下拉去掉后去掉用户切换-去掉电源按键中的紧急呼叫

这里自己倒腾完成了两个常见需求:去除用户切换、去除紧急呼叫UI在去除用户切换时候,用到了Compose知识点,所以很难按照以前经验去找对应布局、找对应的View Item ,以往方法都只能部分借鉴的搞系统的还是要跟着谷歌学一点Compose技能了,方便日常开发调试。

十年饮冰,难凉热血 1459

七天征服AutoSAR/SomeIP_01速成配置并代码生成

本文为AutoSAR中SomeIP配置开发的实操指南摘要,重点介绍通过通信矩阵快速构建SomeIP工程的方法。核心内容包括:1)基于Excel通信矩阵生成系统描述文件(arxml);2)在AutoSAR工具中导入文件自动生成协议栈配置,涵盖ETHIF、SoAd等模块;3)关键报错处理(COM/PDUR/SOAD/SD模块的配置修正);4)SomeIPXF的数据编解码配置;5)SWC组件与RTE任务映射。教程强调"先完成再完美"的实践原则,指导开发者快速生成基础代码框架,为后续协议调试奠定

大叔带刺的博客 303

JVM内存分配规则

JDK8 默认的,新生代(Young)与老年代的比例值为 1:2(该值可以通过参数 -XX:NewRatio来指定)。新生代分为 Eden和两个Survior区域,分别被命名为from和to,以示区分。默认的,Eden:from:to = 8:1:1(可以通过参数-XX:SurvivorRatio来设定)。JVM初始分配的内存由-Xms指定,默认是物理内存的1/64;JVM最大分配的内存由-Xmx指 定,默认是物理内存的1/4。默认空余堆内存小于40%时,JVM就会增大堆直到-Xmx的最大限制;

web18334137065的博客 1589

【论文复现】——基于改进FPFH特征提取的点云模板匹配方法

基于改进FPFH特征提取的点云模板匹配方法 [J]. 应用激光, 2024, 44 (04): 196-204.

点云侠的博客 611

JVM

触发Full gc条件 从年轻代空间(包括Eden和 Survivor 区域)回收内存被称为 Minor GC,对老年代GC称为Major GC,而Full GC是对整个堆来说的,出现Full GC的时候经常伴随至少一次的Minor GC,但非绝对的。Major GC的速度一般会比Minor GC慢10倍以上。 1、System.gc()方法的调用 此方法的调用是建议JVM进行Full GC,虽然只是建议而非一定,但很多情况下它会触发 Full GC,从而增加Full GC的频率,也即增加了间歇性停顿的次数

m0_46269902的博客 343

从DDPM到DDIM:深入解读《Denoising Diffusion Implicit Models》

DDIM发表在ICRL2021上,是DDPM重要的改进之一,能显著提高DDPM的样本质量、减少采样时间,并且能显式控制插值,已经被广泛应用到现在的Diffusion Models上。这篇博客和大家一起详细解读一下DDIM,认识这一伟大的模型。.........

沉迷单车的追风少年 1万+

利用 RSAU_LOG_API 把 SAP 安全审核日志接入企业 SIEM 的完整指南

在 SAP 世界里,安全审核日志(Security Audit Log,简称 SAL)是审计和合规的核心基础设施之一。系统会在后台把安全相关的关键事件记录下来,比如:(用户登录与登录失败用户锁定、解锁权限对象或角色变更远程调用(RFC)相关活动关键事务码的启动程序直接执行、批处理作业相关的敏感操作传统 ABAP 系统里,这些日志会写到本地应用服务器上的审计文件中(背后对应类似表RSAUENTR2的结构),包含事件标识、客户端、用户、终端、事务码、时间戳等信息。

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 161

JVM -Xmx内存设置超过物理内存问题思考

JVM -Xmx内存设置超过物理内存问题思考 文章目录JVM -Xmx内存设置超过物理内存问题思考问题提出理论思考1. 是否可以设置`-Xmx`超过物理内存?2. 是否可以将`-Xmx`设置的无限大?3. 当物理机内存耗尽时,会发生什么现象?4. JVM在堆内存不足和物理内存耗尽时会发生什么?5. JVM会因为临近物理内存大小而发生GC吗问题验证测试代码测试Xmx最大值WindowsLinux测试内存溢出开启SWAP情况下关闭SWAP情况下测试GC现象关闭Swap打开Swap其他说明 问题提出 JVM是否可

明谨的博客 9004

【DaVinci Developer专题】-41-APP SWC如何读取写入NVM Block数据

APP SWC Port如何Read读取/Write写入NVM Block数据; DaVinci Developer中的Calibration Parameter/Per-Instance Memory/Service Need如何配置。

「汽车电子助手」的博客 4471

linux设置jvm内存参数_JVM 与 Linux 的内存关系详解

在一些物理内存为8g的服务器上,主要运行一个Java服务,系统内存分配如下:Java服务的JVM堆大小设置为6g,一个监控进程占用大约 600m,Linux自身使用大约800m。从表面上,物理内存应该是足够使用的;但实际运行的情况是,会发生大量使用SWAP(说明物理内存不够使用 了),如下图所示。由于SWAP和GC同时发生会致使JVM严重卡顿,所以我们要追问:内存究竟去哪儿了?要分析这个问题,理解...

weixin_39604516的博客 2753

Data-Structures-and-Algorithm-Analysis-in-Java.pdf

作者: Weiss, Mark A. 出版社: Addison Wesley Data Structures and Algorithm Analysis in Java is an “advanced algorithms” book that fits between traditional CS2 and Algorithms Analysis courses. In the old ACM Curriculum Guidelines, this course was known as CS7. This text is for readers who want to learn good programming and algorithm analysis skills simultaneously so that they can develop such programs with the maximum amo...

IMSL CNL 7.0.0 (x86-64)Crack

IMSL CNL 7.0.0 (x86-64)Crack intel的算法库破解文件,这是C++版本的破解文件

上一篇: Java大学问——优雅地处理异常
下一篇: 再不懂ZooKeeper,就安安心心把这篇文章看完
大G哥
博客等级 码龄9年 5303粉丝 1408原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值