如何使用ddmlib dump出堆文件

一般情况下如果我想要较详细的分析内存状况,会使用android monitor(下简称monitor)和Memory Analyzer工具(下简称MAT),但步骤有些麻烦。

  1. 使用monitor dump堆文件
  2. 使用hprof-conv工具,将hprof转换成MAT能够识别的格式
  3. 使用MAT分析

需要手动dump hprof再使用hprof-conv工具手动转码,上篇Android Bitmap的内存大小是如何计算的?说到使用square的haha来做内存堆中Bitmap的分析。所以在思考如何一键完成内存dump和analyze的过程,当然也可以任意其他Java对象做分析。
如何完成dump和转码,思路还是Read the fucking source code,看下monitor是如何dump hprof文件的。打开Android sdk目录,monitor和其依赖的jar分别在/tools和’/tools/lib’目录,核心代码在ddmlib.jar中,Java swring代码在ddms.jarddmuilib.jar中,ddmlib需要依赖common.jarguava.jar

如何使用ddmlib获取adb连接的设备

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
public static void main(String[] args) {
IDevice device;
// 这里需要传参true,不然待会会拿不到手机上的client
AndroidDebugBridge.init(true);
AndroidDebugBridge bridge = AndroidDebugBridge.createBridge(
"/Users/Ivonhoe/Library/Android/sdk/platform-tools/adb", false);
waitForDevice(bridge);
IDevice devices[] = bridge.getDevices();
device = devices[0];
}

private static void waitForDevice(AndroidDebugBridge bridge) {
int count = 0;
while (!bridge.hasInitialDeviceList()) {
try {
Thread.sleep(100);
count++;
} catch (InterruptedException ignored) {
}
if (count > 300) {
System.err.print("Time out");
break;
}
}
}

如何dump hprof

这里不说看ddms源码的过程了,主要还是通过关键字搜索跟一下dump操作的处理逻辑

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
/**
* 设置HprofDumpHandler,对dump事件做监听处理dump成功或者失败的回调,
* 并保存hprof文件数据
*
* @param device
*/
public HprofDump(Device device) {
mDevice = device;

ClientData.IHprofDumpHandler hprofDumpHandler = new ClientData.IHprofDumpHandler() {

@Override
public void onSuccess(String remoteFilePath, Client client) {
String hprofPath = getHprofPath(client.getClientData().getClientDescription());
mDevice.pull(hprofPath, remoteFilePath);

conversionAndRemoveHprof(hprofPath);

isDumping = false;
}

@Override
public void onSuccess(byte[] bytes, Client client) {
String hprofPath = getHprofPath(client.getClientData().getClientDescription());
Utilities.saveFile(bytes, hprofPath);

conversionAndRemoveHprof(hprofPath);

isDumping = false;
}

@Override
public void onEndFailure(Client client, String s) {
isDumping = false;
}
};
ClientData.setHprofDumpHandler(hprofDumpHandler);
}

这里默认选择栈顶进程做dump操作,通过adb shell dumpsys activity top命令获取栈顶TASK的ApplicationId,通过IDevice接口的getClient方法获取Client对象,执行dumpHprof操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
/**
* dump栈顶进程的hprof
*/
public void dumpTopTaskHprof() {
if (isDumping) {
return;
}

IDevice iDevice = mDevice.getIDevice();

/**
* 这里自动选择手机上栈顶进程做dump操作,获取applicationName
*/
String topApp = getTopApplication();
Client client = iDevice.getClient(topApp);

if (client == null) {
throw new RuntimeException("Can not dump app:" + topApp);
}
client.dumpHprof();
isDumping = true;
}

在IHprofDumpHandler的回调中, 保存hprof文件,做格式转换,分析Bitmap对象的状况。BitmapAnalyzer.java的代码在上文说过。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
private void conversionAndRemoveHprof(String hprofPath) {
String convHprofPath = getConvHprofPath(hprofPath);
hprofConv(hprofPath, convHprofPath);
removeFile(hprofPath);

analyzerBitmap(convHprofPath);
}

private void hprofConv(String hprofPath, String convHprofPath) {
String adbPath = Adb.instance().getAdbPath();
String hprofConvPath = adbPath.replace("adb", "hprof-conv");
ShellCommand.exec(hprofConvPath + " " + hprofPath + " " + convHprofPath);
}

private void analyzerBitmap(String hprofPath) {
String[] args = new String[2];
args[0] = hprofPath;
args[1] = "bitmap";
BitmapAnalyzer.main(args);
}

转载请标明出处病已blog https://ivonhoe.github.io/