在命令行中使用Eclipse MAT工具
来源:互联网 发布:四六级听力软件 编辑:程序博客网 时间:2024/05/22 15:16
最近应用在测试中出现Out Of Memory的问题, 通过jmap查看,发现JVM heap全用满了。
有很多工具可以查看JVM堆的信息, 收费的比如JProfiler, YourKit,免费的如Oracle JDK自带的visualvm, jhat和Eclipse MAT。
这个应用安装在一台AWS上,没有图形界面, 内存也比较小,想通过VNC远程桌面启动visualvm或者MAT不可能,通过jhat分析dump出来的snapshot(大约4.3G)也很慢,半天没有分析完毕,这种办法也放弃。
最后通过MAT的命令行工具分析了dump出来的snapshot,查找到OOM的元凶。
使用MAT命令行工具
首先通过jstat或者jmap查看heap信息,比如通过jmap查看:
12345678910111213141516171819202122232425262728293031323334353637383940414243
JVM version is 25.31-b07using thread-local object allocation.Parallel GC with 4 thread(s)Heap Configuration:MinHeapFreeRatio = 0MaxHeapFreeRatio = 100MaxHeapSize = 4294967296 (4096.0MB)NewSize = 1431306240 (1365.0MB)MaxNewSize = 1431306240 (1365.0MB)OldSize = 2863661056 (2731.0MB)NewRatio = 2SurvivorRatio = 8MetaspaceSize = 21807104 (20.796875MB)CompressedClassSpaceSize = 1073741824 (1024.0MB)MaxMetaspaceSize = 17592186044415 MBG1HeapRegionSize = 0 (0.0MB)Heap Usage:PS Young GenerationEden Space:capacity = 482344960 (460.0MB)used = 468288384 (446.5946044921875MB)free = 14056576 (13.4053955078125MB)97.08578358525816% usedFrom Space:capacity = 278921216 (266.0MB)used = 0 (0.0MB)free = 278921216 (266.0MB)0.0% usedTo Space:capacity = 477102080 (455.0MB)used = 0 (0.0MB)free = 477102080 (455.0MB)0.0% usedPS Old Generationcapacity = 2863661056 (2731.0MB)used = 2863365080 (2730.7177352905273MB)free = 295976 (0.28226470947265625MB)99.98966441927965% used12340 interned Strings occupying 1051736 bytes.
最多的类的实例:
1234567891011121314
num #instances #bytes class name----------------------------------------------1: 21606534 1530253752 [C2: 21606239 518549736 java.lang.String3: 19198980 460775520 scala.collection.immutable.ListSet$Node4: 4568546 109645104 scala.collection.immutable.HashSet$HashSetCollision15: 103739 63212992 [B6: 1487034 53464560 [Lscala.collection.immutable.HashSet;7: 1487034 35688816 scala.collection.immutable.HashSet$HashTrieSet8: 1350368 32408832 scala.collection.immutable.$colon$colon9: 1090897 26181528 scala.collection.immutable.HashSet$HashSet110: 200035 17603080 akka.actor.ActorCell11: 100536 8042880 java.lang.reflect.Constructor12: 500026 8000416 scala.runtime.ObjectRef
从分析来看猜测是akka actor mailbox里面的字符串消息太多了。
既然没有办法图形化启动visualvm和MAT,那么就使用MAT文件夹下的ParseHeapDump.sh
, 特别适合分析大堆的信息。
首先你需要修改MemoryAnalyzer.ini中的Xmx值,确保有充足的硬盘空间(至少dump文件的两倍)。
然后运行
1
./ParseHeapDump.sh heap.bin org.eclipse.mat.api:suspects org.eclipse.mat.api:overview org.eclipse.mat.api:top_components
会得到suspects, overview和top_components三个视图的信息。
可以看到akka.dispatch.Dispatcher$$anon$1
一个实例占用了2.4GB的内存,这就是罪魁祸首。这其实是akka dispatcher的mailbox中的Java.util.concurrent.ConcurrentLinkedQueue,每个Node占用了81M的内存,
消息体太大了。
编写程序得到所需信息
你也可以引用MAT的类,得到heap dump中的信息, 因为MAT使用Eclipse RCP框架, 基于osgi架构,使用起来不太方便,所以你可以别人抽取出来的MAT库,如https://bitbucket.org/joebowbeer/andromat
,
然后实现一个命令行程序,比如下面的例子就是输出所有的字符串的值:
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152
package com.colobu.mat;import org.eclipse.mat.SnapshotException;import org.eclipse.mat.parser.model.PrimitiveArrayImpl;import org.eclipse.mat.snapshot.ISnapshot;import org.eclipse.mat.parser.internal.SnapshotFactory;import org.eclipse.mat.snapshot.model.IClass;import org.eclipse.mat.snapshot.model.IObject;import org.eclipse.mat.util.ConsoleProgressListener;import org.eclipse.mat.util.IProgressListener;import java.io.File;import java.io.IOException;import java.util.Collection;import java.util.HashMap;public class Main {public static void main(String[] args) throws SnapshotException, IOException {String arg = args[args.length - 1];String fileName = arg;IProgressListener listener = new ConsoleProgressListener(System.out);SnapshotFactory sf = new SnapshotFactory();ISnapshot snapshot = sf.openSnapshot(new File(fileName),new HashMap<String, String>(), listener);System.out.println(snapshot.getSnapshotInfo());System.out.println();String[] classNames = {"java.lang.String"};for (String name : classNames) {Collection<IClass> classes = snapshot.getClassesByName(name, false);if (classes == null || classes.isEmpty()) {System.out.println(String.format("Cannot find class %s in heap dump", name));continue;}assert classes.size() == 1;IClass clazz = classes.iterator().next();int[] objIds = clazz.getObjectIds();long minRetainedSize = snapshot.getMinRetainedSize(objIds, listener);System.out.println(String.format("%s instances = %d, retained size >= %d", clazz.getName(), objIds.length, minRetainedSize));for (int i = 0; i < objIds.length; i++) {IObject str = snapshot.getObject(objIds[i]);String address = Long.toHexString(snapshot.mapIdToAddress(objIds[i]));PrimitiveArrayImpl chars = (PrimitiveArrayImpl) str.resolveValue("value");String value = new String((char[]) chars.getValueArray());System.out.println(String.format("id=%d, address=%s, value=%s", objIds[i], address, value));}}}}
基本上使用ParseHeapDump.sh
已经得到了我所需要的结果,优化akka actor消息的内容解决了我的问题。
参考文档
- https://wiki.eclipse.org/MemoryAnalyzer/Extending_Memory_Analyzer
- http://javaforu.blogspot.jp/2013/11/analyzing-large-java-heap-dumps-when.html
- http://dr-brenschede.de/bheapsampler/
- http://www.techpaste.com/2015/07/how-to-analyse-large-heap-dumps/
- http://stackoverflow.com/questions/15977723/analyse-a-hprof-memory-dump-file-from-command-line-programmically
- http://wangjunyan.github.io/2014/12/02/export-android-bitmap-from-dump-file/
- 在命令行中使用Eclipse MAT工具
- 在命令行中使用 Eclipse MAT 工具
- 在命令行中使用Eclipse MAT工具
- 在 Eclipse 中使用命令行
- 在 Eclipse 中使用命令行
- Eclipse MAT 工具的使用
- eclipse 中使用内存分析工具MAT分析内存泄漏
- 在 PHP 中使用命令行工具
- 在 PHP 中使用命令行工具
- 在 PHP 中使用命令行工具
- 如何在 Eclipse 中使用命令行
- 如何在 Eclipse 中使用命令行
- 如何在 Eclipse 中使用命令行
- 如何在 Eclipse 中使用命令行
- 如何在 Eclipse 中使用命令行
- 如何在 Eclipse 中使用命令行
- 如何在 Eclipse 中使用命令行
- 如何在 Eclipse 中使用命令行
- spring mvc redirect 重定向 跳转并传递参数
- 进程注入后门工具Cymothoa
- TiDB RC3 Release
- iOS
- poj2155 Matrix 二维树状数组
- 在命令行中使用Eclipse MAT工具
- 干货来袭,推荐几款开源的Kotlin的Android项目
- leetcode 628:Maximum Product of Three Numbers
- 计算两个NSDate的时间差,计算毫秒差
- 草根站长心酸路:你的网站后来怎么样了?
- Nth Highest Salary 解法讨论(Mysql)
- 剑指offer——数字在排序数组中出现的次数(复习二分)
- MD5加密算法
- Spark调优之Tuning Spark(Part 2)