Scripting hprof memory dump from emulator, hprof-conv to MAT

Tutorials with advanced 'difficulty' and more Lines of Code.

Scripting hprof memory dump from emulator, hprof-conv to MAT

Postby jonw » Wed Feb 10, 2010 10:50 pm

Been lurking here for a while, thought it time to give something back ;)

When trying to find memory leaks, or diagnose other issues where apps appear to be consuming too much memory, the thing to do is export a memory dump from the emulator to your development machine.

This dump needs to be converted using the hprof-conv tool which comes with the SDK and then loaded into a tool that analyses these dumps -- MAT (made by Eclipse) seems to be the best choice.

This helpful post on biowallet.blogspot.com details the manual steps that need to be done when going through this procedure.

Nothing too tricky, but it's a PITA to repeat. So I wrote the following Perl script to automate the procedure. It requires Perl and will not work on Windows without further modifications. But should work on any unix-like OS -- works for me on FreeBSD & Mac OS X. I call mine "get-hprof.pl"

Code: Select all
$i = $ARGV[$0];
if ($i !~ /w/){print "Must enter package identifier after script namen";exit;}

$vm_fnp = '/data/misc';
print "Looking for package identifier $in";

`adb shell chmod 777 $vm_fnp`; # ensure dumps can be written
$cmd = "adb shell ps | grep ${i} | cut -d' ' -f4"; # find process
$pid = `$cmd`;
chomp $pid;
print "PID = $pidn";
$retval=`adb shell kill -10 $pid`; # send process the magic dump signal
sleep 3; # REQUIRED: give time to kill & dump hprof file

$cmd = "adb shell ls $vm_fnp | grep ${pid}"; # locate the hprof
$ls_rv = `$cmd`;
@files = split(/s+/,$ls_rv); # more portable than adding head -n 1, above
$file = $files[0];
if($file !~ /.hprof/){print "No file found!n";exit};

print "Try: adb pull $vm_fnp/$file .n";
$rval = `adb pull $vm_fnp/$file .`;

($second, $minute, $hour, $dayOfMonth, $month, $yearOffset,
   $dayOfWeek, $dayOfYear, $daylightSavings) = localtime();
$year = 1900 + $yearOffset;$month+=1;
$timestr = "$year-$month-$dayOfMonth-$hour-$minute-$second";
$localfile = "$timestr-$i.hprof";
mkdir ("./$timestr"); # each dump in it's own dir, as MAT creates lots of files there
$cmd = "hprof-conv $file ./$timestr/$localfile"; # un-dalvikify the hprov
`$cmd`;
print "Deleting unconverted dumps on device and locallyn"; # keep it tidy
`rm ./$file`;
`adb shell rm $vm_fnp/$file`;
print "Hopefully wrote $localfile ok :)n";
exit;


Yes, that is quick and very dirty Perl with not enough error checking :)
Sample usage:

$ perl ./get-hprof.pl disco
Looking for package identifier disco
PID = 706
Try: adb pull /data/misc/heap-dump-tm1265828110-pid706.hprof .
1624 KB/s (3573520 bytes in 2.147s)
Deleting unconverted dumps on device and locally
Hopefully wrote 2010-2-10-18-55-27-disco.hprof ok :)
$


Here's what to do;
1) Ensure you are running a unix OS :)
2) Create a new dir somewhere, copy the code to a new text file in that dir, called e.g. "get-hprof.pl". Do "chmod 755 get-hprof.pl" to make it executable.
3) Ensure that the emulator is up, and running your app
4) When you run the script, it needs a "package identifier" so it can find the right process for your app on the emulator. I use the last bit of the Java package name, e.g. my package is "net.int4.disco" so i type "perl ./get-hprof.pl disco" to run the script.

Why? Because in the process list on the emulator, the process running your app will look like:

Code: Select all
# ps
USER     PID   PPID  VSIZE RSS   WCHAN    PC         NAME
root     1     0     280   188   c008de04 0000c74c S /init
root     2     0     0     0     c004b334 00000000 S kthreadd
root     3     2     0     0     c003cf68 00000000 S ksoftirqd/0
...
app_19   706   541   106156 18760 ffffffff afe0d3e4 S net.int4.disco


And that's how the script finds the process ID ("PID") by looking in the process list for the package identifier passed to the script -- in this example that identifier is "disco" which is found in PID "706" at the bottom there. Anyway...

5) Err, that's about it. The script will chmod the directory that the dump gets written to (to ensure it's writeable), find the right process ID based on the identifier you sent as an argument to the script, do a "kill -10 $pid" to generate the dump, copy the dump to the same directory as the script (this may take a few secs), run the dump through the hprof-conv tool so it can be read by MAT, write it to a new sub-directory off the script directory, and delete the raw hprof files from your HD and the emulator.

6) Then, load the result MAT and try to figure out what's going on in your app. But that's another topic ;)
Attachments
get-hprof.pl.zip
The script, zipped.
(1.21 KiB) Downloaded 170 times
User avatar
jonw
Junior Developer
Junior Developer
 
Posts: 24
Joined: Wed Feb 10, 2010 9:00 pm
Location: London

Top

Return to Advanced Tutorials

Who is online

Users browsing this forum: No registered users and 3 guests