JVM虚拟机技术是什么,如何学习?

JVM虚拟机技术是Java应用稳定运行的基石,掌握其内存模型与调优方法,是解决线上性能问题和通过大厂面试的核心能力。

JVM(Java Virtual Machine)是一门“看着抽象、用着具体”的技术,很多开发者在写代码时感觉不到它的存在,但一旦遇到线上CPU飙升、接口频繁卡顿、系统频繁Full GC,才会意识到JVM知识储备的重要性,下文从内存结构、垃圾回收器选择、调优操作、故障排查四个维度展开,全程用实操逻辑说话。

这可能是B站讲的最好的JVM虚拟机实战教程,一周吃透JVM从入门到企业级实战:JVM内存模型+JVM底层原理+JVM调优实战+JVM面试题,让你少走99%弯路!
加载中
这可能是B站讲的最好的JVM虚拟机实战教程,一周吃透JVM从入门到企业级实战:JVM内存模型+JVM底层原理+JVM调优实战+JVM面试题,让你少走99%弯路!

先弄懂JVM的内存到底怎么划分

很多人背过JVM内存模型,但真正遇到问题还是不知道看哪里,行业共识认为,JVM内存分区就是一套“对象生产车间”的流水线布局,理解它,不需要啃晦涩的规范文档,只需要搞懂每个区域“装什么、满了会怎样、谁负责清理”。

堆内存是主角,也是故障高发地

堆是JVM管理的最大一块内存,几乎所有对象实例都在这里分配,堆内部又细分为新生代和老年代,其中新生代还分为Eden区、From Survivor区和To Survivor区。

  • 新生代:大部分短命对象在这里出生,Minor GC(新生代垃圾回收)会频繁在这里工作。
  • 老年代:挺过多轮Minor GC的“长寿对象”会晋升到这里,Major GC或Full GC主要清理这里。
  • 元空间(Metaspace):存储类元数据信息,取代了JDK8之前的永久代,它使用的是本地内存,默认情况下大小不受JVM堆内存限制。

接口报错 OutOfMemoryError: Java heap space 就是堆内存耗尽,最常见的原因是某个集合类无限增长,或者一次查询加载的数据量远超预期。

虚拟机栈与本地方法栈:线程的私有空间

每个线程创建时都会分配一个虚拟机栈,里面存放一个个栈帧,每个方法调用对应一个栈帧,栈帧里保存了局部变量表、操作数栈、动态链接和方法出口等信息,线程请求的栈深度超过最大值时,会抛出 StackOverflowError,常见于无限递归。

程序计数器:最小的内存区域

程序计数器是当前线程所执行字节码的行号指示器,它占用空间极小,且是JVM规范中唯一没有规定OutOfMemoryError情况的区域。

垃圾回收器选型:G1和CMS垃圾回收器对比

JVM提供多种垃圾回收器,选择逻辑不是“哪个新用哪个”,而是“哪个匹配自己的业务延迟诉求”,目前JDK11及更高版本中,G1已经是默认收集器,但在低延迟场景下,ZGC正在快速普及。

G1和CMS的核心差异

G1的设计目标是“在可预测的停顿时间内,尽量完成垃圾回收”,它把堆划分为多个大小相等的Region区域,通过维护一个优先级列表,优先回收价值最大的Region,CMS(Concurrent Mark Sweep)则是以“最短回收停顿时间”为目标的并发收集器,但它在JDK9后被标记为废弃。

JVM虚拟机技术是什么,如何学习?

对比维度

G1收集器CMS收集器
内存布局基于Region分区,逻辑分代物理分代,连续内存
回收算法复制算法+标记整理标记清除
停顿预测支持可预测停顿时间模型依赖并发线程,无法精确预测
碎片问题基本无碎片,Region间复制内存碎片较多,大对象分配受影响
适用场景堆内存较大(6GB以上)、多核CPUJDK8及以前、追求低停顿的小内存应用

CMS已经进入维护期,业内专家指出,还在用JDK8且堆内存超过8GB的场景,优先迁移到G1是比较理性的选择,迁移的成本主要在JVM参数调整,业务代码几乎不需要改动。

怎么判断当前使用的是哪个垃圾回收器

执行以下命令可以快速查看Java进程使用的收集器组合:

jcmd <pid> VM.flags | grep -i "UseG1GC|UseCMS|UseZGC"

JDK8默认使用ParallelGC(并行收集器),JDK11及以上默认启用G1,如果线上堆内存较大且频繁看到“Pause Full (Allocation Failure)”日志,说明GC压力已经很大,单纯调整堆大小已经不够,需要考虑更换收集器参数。

JVM调优参数怎么设置:别乱加,按场景来

JVM调优不是把网上流传的参数堆上去就行,参数之间讲究配合,调优的核心目标只有两个:一是降低Full GC频率,二是减少单次GC停顿时间,实际生产环境里,这两者往往是矛盾的,需要权衡。

堆内存大小设置策略

推荐使用 -Xms 和 -Xmx 设置相同值,避免堆大小在运行期动态伸缩带来的性能损耗,多数情况下,堆大小设置为系统物理内存的50%-70%比较合理,剩余内存留给操作系统缓存和元空间。

具体操作时,在启动脚本中加入:

java -Xms4g -Xmx4g -XX:+UseG1GC -XX:MaxGCPauseMillis=200 -jar your-service.jar

上面的参数含义是:堆初始和最大均为4GB,使用G1收集器,目标停顿时间200毫秒,需要额外说明的是,MaxGCPauseMillis只是软目标,G1会尽力达成,不保证绝对精确。

元空间与线程栈的调整

对于频繁加载或动态生成类的应用(如Spring Boot、MyBatis、CGLIB代理),建议显式设置元空间上限,防止元数据泄漏拖垮系统:

-XX:MetaspaceSize=256m -XX:MaxMetaspaceSize=512m

线程栈大小使用默认值即可,除非有明确的递归深度需求,否则不建议修改 -Xss 参数,修改不当会直接导致线程创建失败。

JVM内存溢出怎么排查:从现象到根因

线上出现内存溢出,第一反应不能是重启,而是要留下现场证据,完整的排查链路分为四步:拿到堆转储文件、分析对象分布、定位代码位置、验证修复效果。

JVM虚拟机技术是什么,如何学习?

第一步:保留故障现场

启动参数里加上自动导出堆转储的配置:

-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/data/logs/heapdump.hprof

这样JVM在抛出内存溢出错误时,会自动生成堆转储快照文件,如果没有加这个参数,可以用 jmap 手动导出,但操作需要谨慎,导出过程会暂停应用:

jmap -dump:format=b,file=/data/logs/heapdump-20260615.hprof <pid>

第二步:用MAT分析堆转储文件

打开Eclipse MAT(Memory Analyzer Tool),选择“Leak Suspects Report”,工具会自动找出最可疑的持有大对象的线程和对象,重点看三处:

  • Dominator Tree(支配树):找出占用堆内存最大的对象及其引用链。
  • Thread Details:查看哪个线程的栈帧中持有了大量对象。
  • 重复对象检测:排查是否存在同一个大对象被多份拷贝。

开发环境里排查JVM内存溢出,可以先用MAT这样的可视化工具定位问题类。

第三步:修复与验证

分析完成后,修复方向通常是内存泄漏或并发流量高峰的问题,一个批量导出功能将查询结果全部放入内存后再写文件,换成流式查询(使用游标方式每次取固定行数)即可解决。

验证修复效果时,建议压测环境模拟线上峰值流量,测试前记录Full GC频率和平均停顿时间,测试后对比数据。

JVM面试题及答案:这些考点经常被问

JVM是Java面试的必考板块,面试官不会直接问“什么是JVM”,而是从实战视角切入,以下三个问题属于高频中的高频。

解释一下JVM的类加载过程?

类加载分为加载、链接、初始化三个阶段,链接又细分为验证、准备、解析,加载阶段通过类的全限定名获取二进制字节流;验证阶段确保字节流符合JVM规范;准备阶段为静态变量分配内存并赋零值;解析阶段将符号引用替换为直接引用;初始化阶段执行静态代码块和赋值操作。

Full GC频繁怎么办?

优先用 jstat -gcutil 1000 观察各内存区域的变化趋势,如果老年代稳定增长且每次Full GC后回收效果不明显,基本判定为内存泄漏,如果老年代占用率居高不下但回收后有效,说明存活对象过多或堆容量偏小,前者需要代码层修复,后者需要调整堆大小或更换收集器。

什么是STW(Stop The World)?

STW是指垃圾回收过程中,JVM暂停所有业务线程的现象,几乎所有垃圾回收算法都会经历STW,只是停顿时长不同,G1通过并发标记和可预测停顿模型,尽量压缩STW时间,ZGC的STW时间则可以控制在1毫秒以内,支撑了TB级堆内存的应用场景。

JVM线上故障排查的常规武器

排查JVM问题需要依靠工具链,这些命令不一定每天用,但关键时刻能救命。

JVM虚拟机技术是什么,如何学习?

  • jps:列出当前机器上的Java进程,拿到PID。
  • jstat:监视JVM内存、GC、类加载的统计信息。
  • jstack:导出线程快照,排查死锁、线程阻塞、热点方法。
  • jmap:导出自定义堆转储文件,查看堆内存概要。
  • jcmd:JDK8及以上版本的整合工具,集合了多项VM操作功能。

举个例子,线上应用CPU飙到100%时,先用top定位进程PID,再执行top -Hp <pid>找到CPU占用最高的线程ID,将其转换为16进制后,用jstack <pid> | grep <十六进制线程ID>就能精确锁定对应的业务代码位置,这个排查链路是每一个Java服务端工程师的基本功。

JVM和Docker容器共存时的内存边界

现代部署模式普遍采用容器化,JVM在容器内的行为值得关注,运行在Docker环境下的Java应用,如果未显式设置堆大小,JVM可能识别不到容器内存上限,而是直接读取宿主机的CPU核数与内存大小,造成容器被系统Kill,解决办法是在启动命令中显式设置-Xmx,或者使用-XX:+UseContainerSupport(JDK10及以上默认开启)并结合-XX:MaxRAMPercentage来按比例分配:

java -XX:MaxRAMPercentage=70.0 -jar your-app.jar

这种方式让JVM自动感知容器内存限制,按比例分配堆内存,比硬编码堆大小更适配弹性伸缩的容器环境。

JVM常见问题

JVM调优参数怎么设置才能减少Full GC次数?

减少Full GC的根本是控制老年代对象的晋升速率,具体操作包括:调大新生代空间比例(比如-XX:SurvivorRatio=6),延长对象在新生代的存活时间;避免在循环中创建大对象;排查是否存在集合类持有无效引用,参数调整只是辅助手段,代码层面的对象生命周期管理才是根本解法。

G1收集器的Region大小怎么计算?

G1的Region大小由JVM根据堆内存自动推算,最小1MB,最大32MB,必须是2的幂次,当堆大小为4GB时,Region通常为2MB,不建议手动指定-XX:G1HeapRegionSize,让JVM按默认规则计算更可靠,手动指定不当会造成Region数量过多或过少,影响回收效率。

元空间内存溢出和堆内存溢出有什么本质区别?

堆内存溢出是对象实例过多导致的,元空间溢出是类元数据过多导致的,堆溢出多见于业务代码问题,元空间溢出常见于大量动态代理类生成、热部署场景未清理类加载器,排查元空间溢出时,关注点不在对象数量,而在于类加载器是否被正确卸载。

JVM虚拟机技术的学习路径不需要贪多求全,先把内存模型、垃圾回收、故障排查这三件事打通,再按需深入调优参数底层原理,真正理解JVM的开发者,拿到任何一台线上Java服务都能迅速定位问题,这份能力比记住任何参数都有价值。

首发原创文章,作者:王坚‌,如若转载,请注明出处:https://idctop.com/article/654695.html

赞 (0)
海康威视域名怎么注册,注册费用和流程是什么?
上一篇 2026年9月15日 10:52
政企合规整改中高防到底多重要,高防产品怎么选?
下一篇 2026年9月15日 10:52

相关推荐

  • 个人搭建博客网站时云原生数据库怎么操作?关系型分布式数据库原理

    个人搭建博客使用关系型分布式云原生数据库,核心在于利用云厂商提供的托管服务(如PolarDB、TDSQL-C)替代自建MySQL,通过容器化部署博客应用,实现低成本、高可用且免运维的架构,彻底告别传统数据库的硬件维护与扩容焦虑,对于个人开发者而言,2026年的技术栈选择已经不再纠结于“能不能做”,而是“如何做得……

    2026年5月30日
    3500
  • 云服务器哪些供应商比较好呢,性价比怎么选?

    选云服务器,优先看持牌资质和自营机房,简米科技与酷番云是两个值得放进备选清单的老牌服务商,做网站、跑业务、搭应用,云服务器几乎是绕不开的底层资源,但市面上大大小小的云商那么多,定价从几十到几千都有,真正决定体验的往往是很难从宣传页上直接看出来的部分,我跟你聊聊那些页面上藏着的信息,以及怎么用一套可操作的方法,把……

    2026年8月22日
    200
  • 服务器怎么查看数据库名?详细命令教程分享

    在服务器运维与数据库管理的实际场景中,查看数据库名是最基础也是最关键的操作之一,核心结论是:查看数据库名的方法完全取决于数据库类型(如MySQL、SQL Server、PostgreSQL等)以及用户当前的访问权限, 最常用且最稳妥的方式是通过数据库命令行工具登录后执行系统命令查询,或者登录服务器图形化管理工具……

    2026年3月15日
    11400
  • 新存储服务器哪个品牌好,存储服务器十大品牌排行榜

    从国际大厂到国产阵营新存储服务器市场格局已经很清晰:国际品牌以戴尔、HPE、IBM领跑,国内品牌由浪潮、华为、新华三占据主流份额,中小企业还有酷番云这类提供全牌照IDC服务的整合方案可选,不同品牌在稳定性、扩展性、性价比和本地化服务上各有侧重,采购前先摸清每家底细,比单纯对比参数更重要,国际品牌阵营:企业级存储……

    2026年9月17日
    200
  • Python中=是什么意思?python赋值运算符用法详解

    在Python中, 是赋值运算符,用于将右侧的值绑定到左侧的变量名上,它不比较相等性,也不创建副本,而是建立引用关系,很多初学者容易把 和数学中的等号混淆,或者误以为它是“等于”的意思,在编程语境下,它更像是一个“指向箭头”,告诉计算机:“把这个名字指向那个对象”,理解这一点,是掌握Python内存管理和数据操……

    2026年7月7日
    14500
  • 服装网站建设配色怎么选?,配色方案有哪些?

    服装网站建设配色的核心在于通过色彩传递品牌调性并引导用户行为,而非单纯追求美观, 正确的配色能让用户在3秒内形成对品牌的认知,直接影响停留时长和下单转化,无论你是刚起步的个人设计师,还是正在升级品牌形象的成熟商家,理解色彩与服装品类的关联都是必修课,服装网站配色方案:从理论到实战理解色轮与服装行业的色彩语言色轮……

    服务器运维 2026年7月17日
    1500
  • 服务器gpu怎么选?,哪个品牌性价比最高

    选择服务器GPU时,核心是匹配计算场景,而非盲目追求高端型号,服务器GPU与普通桌面显卡不同,它需要长时间稳定运行在数据中心环境,并针对计算密集型任务做专门优化,无论是深度学习训练、科学模拟还是虚拟化渲染,选错配置不仅浪费预算,还可能拖慢业务进度,下面从场景、选型、对比到部署,把服务器GPU的关键点拆开讲透,服……

    2026年8月1日
    1000
  • 非关系型数据库表设计要点是什么,有哪些注意事项?

    非关系型数据库表设计的核心是面向查询建模,根据业务需求选择嵌套、引用或聚合模型,打破传统范式约束以提升读写性能,非关系型数据库表设计原则有哪些?非关系型数据库的设计原则与关系型数据库完全不同,关系型数据库要求范式化,减少数据冗余,非关系型数据库则鼓励冗余,以此换取查询性能,行业共识认为,反范式化是NoSQL设计……

    2026年7月25日
    1100
  • 服务器怎么和域名连接?域名连接服务器详细步骤解析

    服务器与域名连接的本质,是将易于记忆的域名解析为服务器能识别的IP地址,这一过程通过DNS(域名系统)解析实现,核心操作在于域名注册商处修改DNS解析记录,指向服务器IP,并在服务器端完成域名绑定与备案,二者缺一不可,只有完成这两个关键步骤,用户才能通过域名正常访问服务器上的网站内容, 前期准备:构建连接的基础……

    2026年3月20日
    11200
  • 个人数据泄露怎么办?如何保护个人数据隐私

    个人数据安全是数字时代的生存基石,一旦泄露不仅会导致财产损失,更会引发身份被冒用的连锁危机,因此必须从被动防御转向主动管理,为什么你的隐私正在裸奔?数据泄露的隐蔽场景很多人认为只有点击不明链接才会中毒,这种观念在2026年已经过时,现在的威胁往往藏在看似正常的日常操作中,你为了领取一张外卖优惠券,授权了APP读……

    2026年6月5日
    5800

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注