Arthas不重启排查:sysprop与heapdump命令实战解析

发布时间:2026/10/22 16:22:21
Arthas不重启排查:sysprop与heapdump命令实战解析 线上某个 Java 服务突然出现诡异现象接口超时、内存曲线像坐了火箭、日志里全是乱码。你第一反应是打开 IDE 连上去看结果发现排查机器是内网隔离别说 IDE连远程调试端口都开不了重启大法倒是能止血但重启完问题可能就再也抓不到了。这种时候我一般会直接退出重启解决一切的思路改用 Arthas 这个 Java 诊断工具挂到目标进程上在不重启、不改代码的前提下把运行时的系统属性和堆内存状态摸清楚。今天这篇就专门讲 Arthas 里两个非常实用、又经常被低估的命令sysprop和heapdump结合我自己实际排查过的场景把用法、原理和坑都拆开讲一遍。适合正在搞 Java 应用运维、或者遇到线上问题但不知道从哪里下手的开发者参考。1. 为什么偏偏是这两个命令先搞清楚它们的定位1.1 生产环境里的黑盒困境很多人第一次接触线上排查时会下意识把问题分成两类一类是配置不对一类是内存不够。这两个方向各自都有传统的排查手段比如查启动脚本里的-D参数、用jmap -dump导堆快照。可真到了生产环境事情没这么简单。先说配置这一类。Java 的配置信息里很大一部分是系统属性System Properties也就是System.getProperties()拿到的那张键值表。它跟启动参数-Dkeyvalue、环境变量Environment Variables是三兄弟但经常被混为一谈。有些问题比如file.encoding不对导致读文件乱码、java.io.tmpdir指向了一个不可写的目录导致上传临时文件失败、user.timezone跟业务期望的时区差了 8 个小时都是系统属性埋的雷。但麻烦的是这些属性在进程启动之后就被焊死了一部分你从外面看启动脚本未必能发现问题因为值可能是在代码里用System.setProperty改过的。再说内存这一类。内存问题最怕的是事发现场已经没了。等你发现内存飙升再去翻监控、猜代码堆里到底是什么对象占着空间早就说不清了。heapdump的价值就是把堆的案发现场完整拍下来让你事后慢慢分析。Arthas 的高明之处在于它把这两类排查能力都塞进了一个命令行工具里进程不用重启、业务代码不用动attach 上去就能查。sysprop负责读改系统属性heapdump负责导出堆快照两把钥匙配合使用能覆盖掉线上排查里相当一部分症状在表面、病根在深处的情况。1.2 这两个命令解决了什么核心痛点我想用一个表格先概括一下它们的定位后面再各自展开维度syspropheapdump作用对象JVM 系统属性表JVM 堆内存核心操作查看、按 key 过滤、修改生成 hprof 堆快照文件典型症状乱码、时区错、临时目录不可用OOM、GC 频繁、内存缓慢上涨排查特点实时、轻量、可反向验证离线分析、信息量大风险等级低修改需谨慎中大堆时会有停顿从我自己的经验看这两个命令最适合的组合套路是症状比较外在的时候先上sysprop用最小代价确认配置有没有问题症状指向内存时再上heapdump把怀疑范围缩小到具体的类和对象。下面我按顺序讲透。2. sysprop 命令实战读取与修改 JVM 系统属性2.1 基础用法先看全量再按 key 定向查询sysprop的使用非常直接。进入 Arthas 交互界面后直接敲sysprop会打印出当前 JVM 里全部的系统属性。在我的机器上一个中等规模的 Spring Boot 应用大概会打出两三百行包括java.version、java.home、os.name、user.dir、file.encoding这些常见项也包括中间件、框架在启动时写入的自定义属性。几百行看着眼花实战中我很少真的去翻全量输出更多是带着疑问定向查。命令格式是sysprop key比如sysprop file.encoding sysprop user.timezone sysprop java.io.tmpdir输出会直接显示 key 对应的 value。如果这个 key 不存在Arthas 会提示查不到这时候要想想是不是拼写问题或者这个属性根本就不是系统属性而是环境变量或应用自定义配置别在sysprop上死磕。有一个细节值得注意sysprop输出的是当前运行时的系统属性而不是启动脚本里写了什么。这意味着它能反映代码里System.setProperty之后的状态。之前我遇到过一个问题启动脚本里明明写了-Dfile.encodingUTF-8但应用日志还是输出 GBK 乱码。用sysprop file.encoding一看运行时值居然是GBK说明有人在代码里重新 set 过。这种启动参数被覆盖的隐蔽场景只有运行时查看才能发现。2.2 修改属性语法很简单生效范围要拎清sysprop不仅能读还能改。语法是在 key 后面直接跟新值sysprop user.timezone Asia/Shanghai sysprop file.encoding UTF-8执行成功后会返回修改后的值。这里必须强调三个容易被忽视的点。第一修改是临时的只对当前进程生效进程重启后就会丢。它本质上是调用了System.setProperty改的是运行内存里的属性表不会回写启动脚本也不会持久化到任何配置文件。所以别指望用它来修复配置更合适的定位是临时验证。第二很多属性在 JVM 启动早期就被读取并缓存到了其他变量里sysprop改了之后未必能立刻影响已经初始化的组件。举个例子file.encoding这个属性比较特殊JDK 在启动时会根据它初始化 Charset 相关的内部状态运行时再改file.encoding已经创建好的 Reader/Writer 和某些编码转换逻辑可能还是老样子。所以如果你想验证改成 UTF-8 之后乱码是否消失最可靠的做法是改完再触发一次相关业务路径观察新创建的流是否正常。第三修改时要克制。sysprop修改属性的操作是有副作用的尤其是在并发环境下一个属性被多个线程读取你改了值可能会导致不可预知的行为。我在生产上只会在影响面可控、能快速回滚重启即恢复的情况下用它更多时候拿它来做理论验证而不是长期修复手段。2.3 实战场景一次由 file.encoding 引发的乱码排查为了让这块内容更具体我讲一个之前处理过的案例。某业务系统在处理用户上传的 CSV 文件时解析出来的中文全是乱码。常规怀疑对象是代码里读取文件时没有指定字符集但翻代码没发现明显问题。我挂上 Arthas先查了运行时属性sysprop file.encoding sysprop sun.jnu.encoding结果是file.encodingGBKsun.jnu.encodingUTF-8。sun.jnu.encoding影响的是文件名的编码file.encoding影响的是文件内容的默认读写编码。这两个值不一致在某些 JDK 版本下就很容易出现文件名正常、内容乱码的现象。问题的根源是某位同事在公共初始化代码里加了System.setProperty(file.encoding, GBK)本来想兼容老系统结果殃及池鱼。我当时没有直接改代码上线而是先用sysprop file.encoding UTF-8在运行态改掉再让业务侧重新上传一次文件确认乱码消失。验证通过后才去改代码、走发布流程。这就是sysprop最典型的用法不重启、不改代码先证明病因在这里再决定怎么治。2.4 与 jinfo 的对比Arthas 强在哪说到看系统属性可能有人会提 JDK 自带的jinfo。确实jinfo -sysprops pid也能打印系统属性而且不用装 Arthas。但我个人的体感是在交互式排查场景里 Arthas 的sysprop更顺手jinfo是一次性命令查一个 key 要敲一遍完整命令sysprop在 Arthas 交互界面里可以连续敲好几条上下文不丢。Arthas 支持 key 前缀补全敲到一半按 Tab 会提示有哪些属性名不用死记硬背。这个体验在记不清sun.jnu.encoding这种冷门 key 的时候特别救命。修改属性的能力也是sysprop的加分项虽然jinfo在特定场景也能改某些 flag但系统属性的运行时修改用 Arthas 更直接。3. heapdump 命令实战把堆内存拍成一张现场照片3.1 基本用法与输出位置heapdump的用途是导出 JVM 堆的 hprof 二进制快照。进入 Arthas 后最简单的用法是heapdump这会在当前工作目录生成一个类似java_pid12345.hprof的文件。我建议你手动指定路径免得 Arthas 的工作目录跟预期不一致文件生成之后找不到heapdump /data/dump/20240615-order-service.hprof还可以通过--live参数只导出存活对象heapdump --live /data/dump/20240615-order-service-live.hprof--live的含义是触发一次 Full GC把堆里的垃圾对象清掉之后只保留存活对象再 dump。这样导出的文件更小分析的时候也不会被大量无用的死对象干扰。但我必须把丑话说在前面--live会带来一次 Full GC 停顿在堆特别大、比如十几个 GB 的实例上这个停顿可能长达数秒甚至更久对线上业务有明显影响。所以我的经验法则是——如果只是怀疑内存泄漏、怀疑大对象优先不加--live先导一个完整快照只有在堆文件实在太大、分析工具打不开或者你能接受一次短暂停顿的时候才考虑--live。3.2 和 jmap 相比heapdump 命令的差异化优势传统导出堆快照用得最多的是jmap -dump:formatb,filexxx.hprof pid。那 Arthas 的heapdump还有什么存在的必要我的答案是方便以及安全。第一jmap对导出时机的掌控能力比较弱经常是命令行一执行立刻 dump缺少跟业务侧的协调空间。而在 Arthas 交互界面里你可以先观察内存变化趋势挑一个相对空闲的时机执行heapdump或者先分析一下对象的增长情况再决定要不要 dump。第二Arthas 的heapdump可以配合它自己的其他命令快速做dump 前判断。比如先用memory命令看堆内存各个区域的使用率再用dashboard看线程和内存概况确认确实需要堆快照了再执行 dump。整套动作在一个会话里完成中间不用切工具排查思路不断档。第三从生产权限角度来说某些环境只开放了应用端口不开放 SSH 直连或者没有 JDK 的jmap权限但允许通过 web 终端进入 Arthas 之类的诊断通道。这种时候heapdump可能是你唯一能触达堆的方式。3.3 拿到 hprof 之后怎么分析才高效生成 hprof 只是开始真正的排查从打开文件才刚开始。我常用的工具是 Eclipse MAT 和 JVisualVM前者做内存泄漏分析非常顺手后者看对象分布更直观。用 MAT 打开 hprof 之后我习惯按这个顺序走先看Overview页面的Leak Suspects报告MAT 会直接用柱状图告诉你哪些对象最可疑。再看Histogram按类名统计实例数量和 Shallow Heap / Retained Heap。Retained Heap 是如果这个对象被回收能释放多少内存这个指标最能反映对象对内存的占用贡献。对怀疑的类点右键查看Merge Shortest Paths to GC Roots / Path to GC Roots看看这个对象是被谁引用住的。如果是Thread或者ThreadLocal引着不放那基本就是线程上下文没清理如果是某个静态集合引着那就是缓存的锅。之前排查一个内存缓慢上涨的问题时我就是通过 Histogram 发现某个自定义缓存类有几十万个实例Retained Heap 占了堆的一大半。再顺着 GC Roots 找上去发现是定时任务里不断往一个静态ConcurrentHashMap塞数据但清理逻辑因为一个异常分支永远走不到最终内存只涨不降。这种结论不 dump 堆单靠猜是根本定位不到的。如果用 JVisualVM打开 hprof 后可以直接看对象页面的实例数排行和堆转储的按类统计。它的好处是图形化做得比较亲切适合快速人肉浏览缺点是内存分析深度不如 MAT复杂引用链还是得到 MAT 里抠。3.4 一个典型场景OOM 前夜的堆快照再分享一个真实遇到过的场景。某个服务每天下午内存就蹭蹭往上涨监控图显示是一个锯齿波——每天都在涨夜里低谷也不回到原点过几天就得重启一次。这种缓慢泄漏最折磨人。我的排查流程是先heapdump导出第一份快照记下时间点然后让服务继续跑过几个小时内存涨到更高位再导第二份快照。把两份快照同时放进 MAT用Compare Base / Compare Tables对比两个 Histogram就能直接看到这段时间里哪个类多出来了多少对象。这种差值分析法比单看一份快照高效得多因为它天然把只增不减的对象筛选出来而这一类对象正是泄漏的高发区。最后定位到是一个外部接口调用的响应对象被放进了本地队列但因为消费线程在异常情况下没有执行remove导致队列只进不出。解决方案是加finally清理、给队列加容量上限。整个过程里heapdump给了我最硬核的证据避免了跟业务团队反复拉扯到底是哪段代码的问题。4. 双命令配合的完整排查链路一个虚构但典型的案例4.1 现象描述与初步判断为了把sysprop和heapdump串起来讲我构造一个综合案例来说明排查思路。假设有一个订单导出服务用户反馈导出的 Excel 文件中文列名乱码同时运维监控发现这个服务的内存占用在过去一周里缓慢上涨GC 频率也越来越高。这其实是两个互相独立的问题但发生在一个进程里就需要一套不重启的排查流程把它们分开确认。挂上 Arthas 之后我通常会先跑两个快速命令摸底sysprop file.encoding memorysysprop确认字符集相关的属性值memory看堆区、非堆区的整体水位。摸底之后再决定下一步往哪走。4.2 先用 sysprop 验证乱码是不是配置问题按第 2 节的思路先查file.encoding发现值是GBK而业务方期望的是 UTF-8。为了确认这确实是乱码的直接原因我在运行态把它改成 UTF-8sysprop file.encoding UTF-8然后让测试同学重新触发一次导出确认乱码消失。到这里乱码问题的根因已经锁定剩下的就是走代码修复流程删掉启动时的错误setProperty或者显式指定导出文件的字符集。这里我要单独说一句不要只满足于改成 UTF-8 之后好了。还要追问一句为什么之前是 GBK否则下次换环境可能复现。我当时就是顺着这条线往前查才发现是某个公共依赖在初始化时写死了GBK属于典型的一个坏人拖垮全家。4.3 再用 heapdump 锁定内存上涨的元凶乱码问题告一段落内存问题继续查。先导一份基线快照heapdump /data/dump/order-export-baseline.hprof让服务继续跑一段时间后再导第二份heapdump /data/dump/order-export-after2h.hprof用 MAT 的 Histogram 对比两份快照发现有一个名叫ExportTaskContext的类实例数量从几千涨到了几十万Retained Heap 增长了近一倍。顺着 GC Roots 看这些对象全被一个静态的ThreadLocal变量引用着。再结合代码排查发现导出任务在finally块里没有执行context.remove()异常分支直接 return 导致 ThreadLocal 里的对象一直被当前线程持有线程池里的线程又不会销毁所以内存只涨不降。这个案例里sysprop和heapdump其实是两种完全不同类型的问题但它们在同一个排查会话里无缝切换——这也是线上诊断工具最理想的状态不需要为每个问题换一套工具链。5. 实操中的高频坑与我的处理习惯5.1 修改系统属性改完一定要验证并恢复sysprop改属性这件事看起来简单但它跟改配置文件的心智模型完全不同。配置文件的修改是持久的而sysprop的修改是进程内的临时状态。一旦你忘了恢复这个被改过的属性就会一直留在内存里影响后续所有依赖它的逻辑。我的习惯是在执行修改前先记下原始值验证结束后要么重启进程恢复要么再通过sysprop key 原始值改回去。尤其是user.timezone、file.encoding这种影响面广的属性改完不恢复很可能会把线上环境带入另一个坑。另外sysprop修改对某些框架可能无效甚至有害。比如框架在启动时已经把file.encoding读走并缓存到自己的配置对象里你从外部改系统属性表框架内部依然用旧值。这种情况下不要硬来老老实实改代码和启动参数。5.2 heapdump 的时机和文件管理是最容易翻车的地方heapdump最大的坑不是命令本身而是什么时候执行和导出的文件放哪。大堆实例上dump 过程本身要遍历堆对象期间可能会导致应用响应变慢尤其在不加--live时也要注意虽然普通 dump 的停顿通常比--live小但堆特别大时依然有明显的 CPU 和内存开销。所以我建议在业务低峰期执行或者提前跟业务方打个招呼。文件管理同样重要。一个几 GB 的堆导出的 hprof 也可能接近这个量级生产环境磁盘不够导致导出失败的情况我遇过不止一次。现在我的固定动作是dump 前先df -h看磁盘剩余再指定一个空间充足的绝对路径dump 完立刻分析分析完及时删除避免 hprof 把磁盘塞满。这里给一个我自己常用的命令顺序供参考# 1. 看堆水位 memory # 2. 确认磁盘空间 # 在 Arthas 里可以执行 !df -h外部命令 # 3. 导出完整堆快照 heapdump /data/dump/app-$(date %Y%m%d%H%M).hprof # 4. 如果需要存活对象快照单独导出 heapdump --live /data/dump/app-live.hprof5.3 敏感信息与权限管控堆快照里有敏感数据这个很多人会忽略。hprof 文件本质上是内存的二进制快照里面可能包含用户手机号、身份证号、业务密钥、数据库连接串等一切驻留在堆里的信息。把 hprof 直接丢给第三方分析或者上传到不安全的存储都是很大的安全隐患。我的处理习惯是hprof 文件只在需要分析的人员范围内流转分析完优先用安全删除方式处理如果必须留档会先做脱敏或者限制访问权限。Arthas 本身在进入交互会话时也建议做好权限控制避免非授权人员 attach 到生产 JVM 上乱操作。sysprop虽然不涉及堆内容但它能暴露 JVM 启动参数和部分环境相关属性对排查有帮助但也算敏感面的一部分。总的原则是诊断工具给了你很大的操作权限权限越大越要自律只做必要的最小操作。5.4 两个命令的转储能力对比小结最后用一个表格把这两个命令的关键差异再收拢一下方便你以后快速查阅对比项syspropheapdump常用子命令无子命令靠参数区分读/写--live控制是否只导存活对象执行耗时毫秒级秒级到分钟级看堆大小对业务影响极小可能有明显停顿大堆更明显输出物控制台文本hprof 二进制文件常用分析工具Arthas 控制台Eclipse MAT / JVisualVM后续恢复手段手动改回或重启无需恢复但要及时清理文件6. 写在最后的个人体会sysprop和heapdump单独拿出来都不复杂花十分钟看一遍官方文档就能上手但真正让它们发挥价值的是使用时的克制和思路。sysprop适合做快速验证而不是紧急修复改之前想清楚影响面改之后记得恢复heapdump适合做事后取证别在症状发生时手忙脚乱先导基线、再导对比用差值去缩小怀疑范围比对着一份快照瞎猜有效得多。我自己在无数次线上排查里形成的习惯是先花五分钟把所有能快速获得的运行时信息摸一遍包括系统属性、内存水位、线程状态再决定要不要上重型手段。很多时候问题在sysprop这一步就找到了根本等不到heapdump出场。但一旦内存类问题真的出现手里有一份高质量的 hprof就等于有了跟同事、跟上级沟通时最硬气的证据。工具永远是辅助真正值钱的是你脑子里那条清晰的排查链路。希望这篇能把这两个命令的用法和边界讲清楚下次你在线上碰到乱码或者内存疑难杂症的时候能少走几步弯路。

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询