jmap 几个慎用操作

最近中大招了,前一周开始偶尔在线上发现一些请求时长竟长达7秒,甚至在部分时段系统存在周期性的请求失败或者超时,各种招式都使用了还是不知道确切的原因,百思不得其解,头大的很!昨日晚上发现这个问题简直太严重了,必须要马上处理掉,一会都耽误不得,遂持续奋斗到晚上一点多,早晨7点多又跑起来搞,用各种手段来找到问题的产生规律,一直到下午1点多,才终于发现症结所在了!

应用服务上曾经出现过Load突然升高,并且伴随OOM,遂加上了一个crontab定时任务,通过jmap来检查老年代的使用情况,有到达快fullgc的点就告警出来,好立马人工来检查,上述问题倒是解决了,但是crontab任务没有取消,才有了今天的恶果!

线上服务器怎么能够出现这种低级问题呢?后悔得要命!

以下为从网上转载的一篇文章,也有提到这个,留在这里好随时提个醒!××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××

转载自:http://hellojava.info/?p=328&utm_source=tuicool

JDK中带有了一堆的工具是可以用来查看运行状况,排查问题的,但对于这些工具还是要比较清楚执行后会发生什么,否则有可能会因为执行了一个命令就导致严重故障,重点讲下影响比较大的jmap。

最主要的危险操作是下面这三种:
1. jmap -dump
这个命令执行,JVM会将整个heap的信息dump写入到一个文件,heap如果比较大的话,就会导致这个过程比较耗时,并且执行的过程中为了保证dump的信息是可靠的,所以会暂停应用。

2. jmap -permstat
这个命令执行,JVM会去统计perm区的状况,这整个过程也会比较的耗时,并且同样也会暂停应用。

3. jmap -histo:live
这个命令执行,JVM会先触发gc,然后再统计信息。

上面的这三个操作都将对应用的执行产生影响,所以建议如果不是很有必要的话,不要去执行。

另外,在排查问题的时候,对于保留现场信息的操作,可以用gcore [pid]直接保留,这个的执行速度会比jmap -dump快不少,之后可以再用jmap/jstack等从core dump文件里提取相应的信息,不过这个操作建议大家先测试下,貌似在有些jdk版本上不work。

之前碰到过一次语言集的问题,我们的Java应用多数在做字符串转码的时候是没有指定编码的,编码信息主要靠启动脚本里面设置LANG来控制,但没想到在某种场景下,竟然有地方设置了LC_ALL,在之前的一篇语言集的文章中,有讲过LC_ALL的优先级是最高的,所以导致启动脚本里设置的LANG失效了,从而导致了乱码,这个Case来看,对于Java应用,还是在启动参数上指定下-Dfile.encoding比较安全一点,避免这种默认的转码依赖系统的配置,很容易踩进坑里。

<think>我们被要求使用jmap -histo命令只查看内存使用最多的几个对象。jmap -histo命令默认会输出所有类的统计信息,按总内存占用(字节数)从大到小排序。因此,最前面的几行就是内存使用最多的对象。 但是,jmap -histo命令本身并没有提供参数来限制输出的行数。所以,我们需要结合其他命令(如head)来只显示前几行。 在Linux或Unix系统中,我们可以使用管道(pipe)将jmap -histo的输出传递给head命令,以显示前N行(例如前10行): ```bash jmap -histo <PID> | head -n 20 ``` 注意:这里使用`head -n 20`是因为jmap -histo的输出前面有3行标题(num, instances, bytes, class name),所以我们显示20行实际上包含了标题和17个对象(因为标题占3行,后面的17行是对象信息)。如果我们只想显示前10个对象(加上标题3行,总共13行),我们可以用: ```bash jmap -histo <PID> | head -n 13 ``` 在Windows系统中,由于没有head命令,我们可以使用`more`命令来分页显示,但more无法精确控制行数。我们可以使用以下方法: 1. 将输出重定向到一个临时文件,然后用文本编辑器查看前几行。 2. 使用PowerShell的命令来获取前几行: ```powershell jmap -histo <PID> | Select-Object -First 13 ``` 但需要注意的是,在Windows上,jmap命令的输出可能不是直接到标准输出的,可能需要先输出到文件再查看。或者我们可以使用: ```powershell jmap -histo <PID> > temp.txt Get-Content temp.txt -TotalCount 13 ``` 另外,我们也可以使用`jmap -histo:live <PID>`来只统计存活的对象,但这会触发一次Full GC,可能会暂停应用。 所以,总结如下: 在Linux/Unix中查看内存使用最多的前10个对象(包含标题): ```bash jmap -histo <PID> | head -n 13 ``` 在Windows中,我们可以使用PowerShell: ```powershell jmap -histo <PID> | Select-Object -First 13 ``` 或者(如果上面的管道不行): ```powershell jmap -histo <PID> > temp.txt; Get-Content temp.txt -TotalCount 13; Remove-Item temp.txt ``` 注意:<PID>是Java进程的进程ID。 此外,引用中提到使用jmap -heap在某些情况下可能会导致进程变T(挂起),尤其是在使用CMS GC的情况下[^3]。因此,如果是在生产环境中,需要谨慎使用。另外,使用jmap -histo:live会触发Full GC,所以也需要慎重。 如果只想查看存活的对象(并且不介意触发Full GC),可以加上`:live`选项: ```bash jmap -histo:live <PID> | head -n 13 ``` 但是,在需要避免Full GC的场景下,就不要使用`:live`。 所以,为了安全起见,如果不需要立即触发GC,就不使用`:live`。 另外,我们还可以使用`jcmd`工具来替代jmap,因为jcmd更强大且对进程影响较小。例如,使用jcmd生成类直方图: ```bash jcmd <PID> GC.class_histogram | head -n 13 ``` 同样,加上`-all`选项可以包括所有对象(包括不可达的),但默认是存活的对象(也会触发Full GC)。所以,如果不加`-all`,则jcmd的GC.class_histogram相当于jmap -histo:live。 因此,如果不想触发Full GC,jcmd也没有直接的办法(除非使用-all,但是-all会包括所有对象,不触发GC,但jcmd的GC.class_histogram默认不带-all,所以它会触发Full GC)。所以,在不触发GC的情况下,我们还是使用jmap -histo(不带live)并配合head。 最后,提醒:执行这些命令需要与运行Java进程相同的用户权限,通常需要与Java进程相同的用户执行。 根据引用[1]和[3],我们了解到: 1. 使用jmap -heap在某些GC条件下可能导致进程挂起,所以避免使用[^3]。 2. 使用jmap -histo可以查看堆内存中的对象情况,帮助发现内存泄露[^1]。 因此,我们建议使用: jmap -histo <PID> | head -n 13 (在Linux上) jmap -histo <PID> 然后手动查看前几行(在Windows上,或者使用PowerShell截取) 如果系统允许短暂的暂停,并且想要查看存活对象,可以使用live选项。 下面我们将这个问题按照步骤总结。 </think>要使用`jmap -histo`命令只查看内存占用最多的几个对象,可通过以下两种方法实现: ### 方法1:管道 + head命令(Linux/Mac) ```bash jmap -histo <PID> | head -n 15 ``` - **原理**: `jmap -histo`的输出默认按内存占用**倒序排列**(最大内存对象在最前),通过`head -n 15`截取前15行(含3行表头 + 12个对象)[^1]。 - **输出示例**: ``` num #instances #bytes class name --------------------------------------------- 1: 1000000 200000000 java.lang.Object 2: 500000 150000000 [B (byte数组) 3: 300000 90000000 java.util.HashMap$Node ...(仅显示前12个对象) ``` ### 方法2:导出到文件 + 筛选(Windows/Linux通用) ```bash jmap -histo <PID> > objects.txt && cat objects.txt | head -n 15 ``` 1. 导出完整统计到文件:`jmap -histo PID > objects.txt` 2. 打开文件后**直接查看前几行**(默认已排序) > ⚠️ 注意事项: > 1. **避免使用`-histo:live`**:添加`:live`会触发Full GC,严重影响性能[^3] > 2. **谨慎执行时机**:在生产环境建议在低峰期操作 > 3. **权限要求**:需与JVM进程相同的用户权限 > 4. **PID获取**:使用`jps -l`或`ps -ef | grep java`查询进程ID ### 内存分析建议 1. 关注**Top 10对象**:特别是非基础类(如自定义类) 2. 对比多次结果:在不同时间点dump并比较对象增长趋势[^1] 3. 结合`jstat`监控:使用`jstat -gcutil <PID> 1000`实时观察GC情况[^4] 4. 可疑对象特征: - 实例数远超预期 - 单对象内存极大(如大数组) - 未被释放的缓存对象
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值