news 2026/4/15 23:23:31

JVM内存监测工具JConsole实战

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
JVM内存监测工具JConsole实战

本文采用“理论阐述 → JConsole验证 → 实战分析”的三段式结构,确保每个抽象概念都能通过可视化工具得到直观验证。


第一部分:JConsole入门与环境准备

1.1 JConsole简介与启动

JConsole是JDK自带的图形化监控工具,可以实时监控JVM内存、线程、类加载等情况。

启动方式:

# 方式1:直接启动,然后连接本地或远程JVMjconsole# 方式2:启动时指定目标进程jconsole<pid>

(实操步骤1:启动演示程序)

先准备一个演示程序,用于后续的监控分析:

publicclassMemoryMonitorDemo{privatestaticList<byte[]>memoryHog=newArrayList<>();publicstaticvoidmain(String[]args)throwsException{System.out.println("演示程序启动,PID: "+ProcessHandle.current().pid());System.out.println("在10秒内打开JConsole并连接此进程...");// 等待JConsole连接Thread.sleep(10000);// 阶段1:模拟内存分配simulateMemoryAllocation();// 阶段2:模拟GC压力simulateGCPressure();Thread.sleep(30000);// 保持运行以便观察}privatestaticvoidsimulateMemoryAllocation(){for(inti=0;i<10;i++){// 每次分配5MBmemoryHog.add(newbyte[5*1024*1024]);try{Thread.sleep(1000);}catch(InterruptedExceptione){e.printStackTrace();}}}privatestaticvoidsimulateGCPressure(){// 创建大量短命对象,制造GC压力for(inti=0;i<1000;i++){byte[]shortLived=newbyte[2*1024*1024];// 2MB短命对象// 立即释放引用,让对象变成垃圾shortLived=null;if(i%100==0){System.gc();// 建议GC,但不保证立即执行}}}}

编译运行:

javac-encoding UTF-8MemoryMonitorDemo.java java-Xmx100m-Xms100m-XX:+UseG1GCMemoryMonitorDemo

第二部分:内存结构可视化分析

2.1 堆内存结构实战观察

理论回顾:

  • 新生代:Eden + 2个Survivor区
  • 老年代:长期存活对象
  • 元空间:类元数据(JDK8+)

JConsole操作步骤:

  1. 启动JConsole并连接演示程序
  2. 进入"内存"标签页
  3. 选择"堆内存使用情况"

下图梳理了程序逻辑、关键内存区域与监控视图的对应关系:


图1:堆内存使用量 (概览)

  • 图表含义:展示了整个堆内存的使用趋势。

  • 程序关联:对应程序的两个主要阶段。

    • 第一阶段(平稳上升):执行simulateMemoryAllocation(),循环10次,每次分配5MB并持有引用。图表中堆内存从低点逐步增长到约 50-60 MB(10 * 5MB + 程序基础占用),这与代码逻辑完全吻合。
    • 第二阶段(剧烈波动下降):执行simulateGCPressure(),创建大量2MB的短命对象并立即弃用,同时每100次循环建议一次GC。图表呈现剧烈的锯齿状波动,这是G1垃圾收集器在工作,频繁回收新生成的垃圾对象。最后的陡降至低位,是程序运行结束,JVM进行最终清理(Final GC)。
图2:内存池 “G1 Eden Space”

  • 图表含义:展示了G1垃圾收集器中年轻代的Eden区使用情况。

  • 程序关联:绝大部分新创建的对象都会先分配在Eden区。

    • 图表中频繁出现的、剧烈的、类似心跳的“锯齿波”,正是第二阶段GC压力测试的典型特征。每个“波峰”代表瞬间分配了大量2MB的短命对象(byte[] shortLived = new byte[2 * 1024 * 1024]);紧接着的“波谷”代表一次Young GC(G1 Young Generation),回收了这些刚变成垃圾的对象。
    • 第一阶段的内存分配(每次5MB)也可能在这里引发数次Young GC,但波动不如第二阶段剧烈。
图3:内存池 “G1 Old Gen”

  • 图表含义:展示了G1垃圾收集器中老年代的使用情况。

  • 程序关联

    • 第一阶段,由于您分配的5MB数组被memoryHog这个静态变量持续引用,它们是长期存活的对象。因此在几次Young GC后,这些对象会从年轻代晋升(Promote)到老年代。图表中老年代使用量从0开始阶梯式稳步增长,正反映了这个过程。
    • 最后阶段,程序运行结束,静态变量memoryHog失效,老年代中的这些对象也不再被引用,因此在一次Full GC / Mixed GC中被彻底回收,图表线断崖式下跌至0。
图4:内存池 “G1 Survivor Space”

  • 图表含义:展示了G1垃圾收集器中年轻代的Survivor区(存活区)使用情况。

  • 程序关联:Survivor区用于存放在一次Young GC中存活下来的、但还未达到晋升年龄的对象。您的程序特点决定了很少有对象能在这里长期存活:

    • 第一阶段的对象会直接晋升到老年代。
    • 第二阶段的对象几乎都是“短命”的,会在Young GC中被直接回收。
    • 因此,该图表显示Survivor区的使用量大部分时间极低,仅在极少数GC发生时可能有短暂的、少量的占用(图表中的小波峰),随后很快又被清空或晋升。
2.2 非堆内存分析

理论回顾:

  • 方法区/元空间:类信息、常量池等
  • 代码缓存:JIT编译后的本地代码
  • 压缩类空间:类指针压缩
图5:非堆内存使用量 (概览)

  • 图表含义:展示了非堆内存(主要是元空间 Metaspace)的使用趋势。
  • 程序关联:非堆内存用于存储类元数据、常量池等。图表显示其使用量在程序运行期间基本保持稳定(约11MB),在程序最终结束时才被回收(骤降至接近0)。这符合预期,因为您的程序没有动态加载/卸载大量类。
图6:内存池 “Metaspace”

  • 图表含义:展示了元空间的使用详情,它是图5“非堆内存”的主要组成部分。
  • 程序关联:与图5解读一致。存储已加载的类信息。您的程序类数量固定,所以曲线平稳。程序结束时的下降与图2的非堆内存下降是同一事件。
图7 & 图8:内存池 “CodeHeap”

  • 图表含义:展示了JVM中JIT编译器生成的本地代码的缓存区使用情况。profiled nmethodsnon-nmethods是不同编译状态和类型的代码存储区域。

  • 程序关联:当JVM运行一段时间后,JIT编译器会将热点Java字节码编译成本地机器码,以提高执行速度。这些编译后的代码就存储在CodeHeap中。

    • 图表中出现的波动,反映了在程序运行期间,JIT编译器在不断工作,编译新的方法,也可能淘汰一些不常用的编译代码。
    • 程序结束时,这些内存被一并释放。

第三部分:GC机制可视化监控

3.1 GC算法与回收器选择

理论(详细信息可以看我上一篇帖子,里面有对理论知识的详细讲解):

现代JVM采用分代收集理论,不同区域使用不同算法:

内存区域推荐算法特点适用场景
新生代复制算法无碎片,高效对象朝生夕死
老年代标记-整理空间利用率高对象存活时间长
3.2 JConsole中的GC监控

启动演示程序时添加GC日志参数:

java -Xmx100m -Xms100m -XX:+UseG1GC -XX:+PrintGC -XX:+PrintGCDetails -Xloggc:gc.log MemoryMonitorDemo

JConsole GC监控操作:

  1. 查看"概要"页签:查看JVM参数和正常运行时间
  2. 查看"内存"页签:实时观察各内存池变化
  3. 查看"VM摘要":了解GC收集器信息

(实操步骤2:GC活动对比实验)

创建两个终端,分别运行不同GC策略的程序:

终端1(G1GC):

java -Xmx100m -Xms100m -XX:+UseG1GC -XX:+PrintGC GCDemo

终端2(Parallel GC):

java -Xmx100m -Xms100m -XX:+UseParallelGC -XX:+PrintGC GCDemo

GCDemo.java:

publicclassGCDemo{publicstaticvoidmain(String[]args)throwsException{List<byte[]>list=newArrayList<>();while(true){// 混合分配大小对象for(inti=0;i<100;i++){list.add(newbyte[1024]);// 1KB小对象}list.add(newbyte[2*1024*1024]);// 2MB大对象Thread.sleep(10);// 模拟对象死亡if(list.size()>1000){list.subList(0,500).clear();}}}}

观察差异:

  • G1GC:停顿时间相对均匀,增量式回收
  • Parallel GC:吞吐量高,但停顿时间可能较长

第四部分:内存泄漏诊断实战

4.1 内存泄漏模式识别

理论:内存泄漏的典型特征是老年代使用率持续上升,即使Full GC后也不释放。

创建内存泄漏演示:

publicclassMemoryLeakDemo{privatestaticMap<Key,String>cache=newHashMap<>();staticclassKey{privateStringid;publicKey(Stringid){this.id=id;}// 错误:没有重写equals和hashCode// 正确的Key应该重写这两个方法}publicstaticvoidmain(String[]args)throwsException{System.out.println("内存泄漏演示开始...");intcount=0;while(true){// 每次使用不同的Key对象(但逻辑上相同)Keykey=newKey("key-"+(count%100));cache.put(key,"value-"+count);if(count%1000==0){System.out.println("Cache size: "+cache.size());System.out.println("内存使用: "+(Runtime.getRuntime().totalMemory()-Runtime.getRuntime().freeMemory())/1024/1024+"MB");}count++;Thread.sleep(10);}}}

运行:

java -Xmx50m -Xms50m -XX:+HeapDumpOnOutOfMemoryError MemoryLeakDemo
4.2 使用JConsole检测内存泄漏

诊断步骤:

  1. 监控堆内存趋势

    • 在JConsole中观察"已使用堆"曲线
    • 内存泄漏特征:锯齿形上升(每次GC后最低点都比前一次高)
  2. 执行手动GC测试

    • 点击"执行GC"按钮
    • 观察内存回收效果:如果无法回收到稳定水平,可能存在泄漏
  3. 分析内存池分布

    • 重点观察老年代:如果持续增长,说明长生命周期对象在积累

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/13 7:39:29

VLAN划分后依然互通?这些常见“误配置”是罪魁祸首

号主&#xff1a;老杨丨11年资深网络工程师&#xff0c;更多网工提升干货&#xff0c;请关注公众号&#xff1a;网络工程师俱乐部你明明建了 VLAN10、VLAN20&#xff0c;把不同部门的设备分别放进去&#xff0c;还特意做了接口隔离。结果对方还能 ping&#xff0c;你傻眼了&…

作者头像 李华
网站建设 2026/4/11 17:02:05

SpringBoot源码剖析

源码剖析 - 依赖管理问题 1&#xff1a;为什么导入 dependency 时不需要指定版本&#xff1f;在 Spring Boot 项目中&#xff0c;pom.xml 核心依赖为 spring-boot-starter-parent 和 spring-boot-starter-web&#xff0c;其中 spring-boot-starter-parent 是版本管理的核心&…

作者头像 李华
网站建设 2026/4/14 5:07:06

Tabula完整使用教程:快速从PDF提取表格数据的终极指南

Tabula完整使用教程&#xff1a;快速从PDF提取表格数据的终极指南 【免费下载链接】tabula Tabula is a tool for liberating data tables trapped inside PDF files 项目地址: https://gitcode.com/gh_mirrors/ta/tabula Tabula是一款革命性的开源工具&#xff0c;专门…

作者头像 李华
网站建设 2026/4/15 20:01:08

ANSYS Fluent完整教程:从零基础到流体动力学模拟高手

ANSYS Fluent完整教程&#xff1a;从零基础到流体动力学模拟高手 【免费下载链接】Fluent中文帮助文档1-28章完整版分享 本仓库提供了一个名为“Fluent中文帮助文档(1-28章)完整版精心整理%09包含19章、21章、24章.pdf”的资源文件下载。该文档是ANSYS Fluent的中文帮助文档&am…

作者头像 李华
网站建设 2026/4/15 20:01:06

Balena Etcher终极使用指南:轻松搞定镜像烧录

还在为系统镜像烧录烦恼吗&#xff1f;Balena Etcher这款开源神器将彻底改变您的体验&#xff01;作为一款专业的跨平台镜像写入工具&#xff0c;Etcher让复杂的系统部署变得简单直观&#xff0c;无论您是初学者还是专业人士&#xff0c;都能在几分钟内完成各种操作系统的烧录任…

作者头像 李华
网站建设 2026/4/14 21:44:00

Windows HEIC缩略图终极解决方案:告别文件预览困扰的完整指南

Windows HEIC缩略图终极解决方案&#xff1a;告别文件预览困扰的完整指南 【免费下载链接】windows-heic-thumbnails Enable Windows Explorer to display thumbnails for HEIC files 项目地址: https://gitcode.com/gh_mirrors/wi/windows-heic-thumbnails 还在为Windo…

作者头像 李华