216 lines
		
	
	
		
			7.5 KiB
		
	
	
	
		
			HTML
		
	
	
	
			
		
		
	
	
			216 lines
		
	
	
		
			7.5 KiB
		
	
	
	
		
			HTML
		
	
	
	
| <html>
 | |
| <head>
 | |
|     <title>Dalvik Heap Profiling</title>
 | |
| </head>
 | |
| 
 | |
| <body>
 | |
| <h1>Dalvik Heap Profiling</h1>
 | |
| 
 | |
| <p>
 | |
| The Dalvik virtual machine can produce a complete dump of the contents
 | |
| of the virtual heap.  This is very useful for debugging memory usage
 | |
| and looking for memory leaks.  Getting at the information can be tricky,
 | |
| but has become easier in recent releases.
 | |
| </p><p>
 | |
| In what follows, the version number refers to the software release
 | |
| running on the phone.  To take advantage of the DDMS integration, you will
 | |
| also need a sufficiently recent version of DDMS.
 | |
| 
 | |
| 
 | |
| <h2>Getting the data</h2>
 | |
| <p>
 | |
| The first step is to cause the VM to dump its status, and then pull the hprof
 | |
| data off.  The exact manner for doing so has changed over time.
 | |
| </p><p>
 | |
| There is a <code>runhat</code> shell function, added by
 | |
| <code>build/envsetup.sh</code>, that partially automates these steps.  The
 | |
| function changes in each release to accommodate newer behavior, so you have
 | |
| to be careful that you don't use the wrong version.
 | |
| </p><p>
 | |
| 
 | |
| <h3>Early releases (1.0/1.1)</h3>
 | |
| <p>
 | |
| You can only generate heap data on the emulator or a device with root
 | |
| access, because of the way the dump is initiated and where the output
 | |
| files go.
 | |
| </p><p>
 | |
| Get a command shell on the device:
 | |
| <blockquote><pre>
 | |
| $ adb shell
 | |
| </pre></blockquote>
 | |
| </p><p>
 | |
| You can verify that you're running as root with the <code>id</code> command.
 | |
| The response should look like <code>uid=0(root) gid=0(root)</code>.  If not,
 | |
| type <code>su</code> and try again.  If <code>su</code> fails, you're out
 | |
| of luck.
 | |
| 
 | |
| </p><p>
 | |
| Next, ensure the target directory exists:
 | |
| <blockquote><pre>
 | |
| # mkdir /data/misc
 | |
| # chmod 777 /data/misc
 | |
| </pre></blockquote>
 | |
| 
 | |
| </p><p>
 | |
| Use <code>ps</code> or DDMS to determine the process ID of your application,
 | |
| then send a <code>SIGUSR1</code> to the target process:
 | |
| 
 | |
| <blockquote><pre>
 | |
| # kill -10 <pid>
 | |
| </pre></blockquote>
 | |
| 
 | |
| </p><p>
 | |
| The signal causes a GC, followed by the heap dump (to be completely
 | |
| accurate, they actually happen concurrently, but the results in the heap
 | |
| dump reflect the post-GC state).  This can take a couple of seconds,
 | |
| so you have to watch for the GC log message to know when it's complete.
 | |
| </p><p>
 | |
| Next:
 | |
| 
 | |
| <blockquote><pre>
 | |
| # ls /data/misc/heap-dump*
 | |
| # exit
 | |
| </pre></blockquote>
 | |
| 
 | |
| </p><p>
 | |
| Use <code>ls</code> to check the file names, then <code>exit</code> to quit
 | |
| the device command shell.
 | |
| 
 | |
| </p><p>
 | |
| You should see two output files, named
 | |
| <code>/data/misc/heap-dump-BLAH-BLAH.hprof</code> and
 | |
| <code>.hprof-head</code>, where BLAH is a runtime-generated value
 | |
| that ensures the filename is unique.  Pull them off of the device and
 | |
| remove the device-side copy:
 | |
| 
 | |
| <blockquote><pre>
 | |
| $ adb pull /data/misc/heap-dump-BLAH-BLAH.hprof tail.hprof
 | |
| $ adb pull /data/misc/heap-dump-BLAH-BLAH.hprof-head head.hprof
 | |
| $ adb shell rm /data/misc/heap-dump-BLAH-BLAH.hprof /data/misc/heap-dump-BLAH-BLAH.hprof-head
 | |
| </pre></blockquote>
 | |
| 
 | |
| </p><p>
 | |
| Merge them together and remove the intermediates:
 | |
| 
 | |
| <blockquote><pre>
 | |
| $ cat head.hprof tail.hprof > dump.hprof
 | |
| $ rm head.hprof tail.hprof
 | |
| </pre></blockquote>
 | |
| 
 | |
| </p><p>
 | |
| You now have the hprof dump in <code>dump.hprof</code>.
 | |
| </p><p>
 | |
| 
 | |
| 
 | |
| <h3>Android 1.5 ("Cupcake")</h3>
 | |
| <p>
 | |
| Some steps were taken to make this simpler.  Notably, the two output
 | |
| files are now combined for you, and a new API call was added that allows
 | |
| a program to write the dump at will to a specific file.  If you're not
 | |
| using the API call, you still need to be on an emulator or running as root.
 | |
| (For some builds, you can use <code>adb root</code> to restart the adb
 | |
| daemon as root.)
 | |
| </p><p>
 | |
| The basic procedure is the same as for 1.0/1.1, but only one file will
 | |
| appear in <code>/data/misc</code> (no <code>-head</code>), and upon
 | |
| completion you will see a log message that says "hprof: heap dump completed".
 | |
| It looks like this in the log:
 | |
| 
 | |
| <blockquote><pre>
 | |
| I/dalvikvm(  289): threadid=7: reacting to signal 10
 | |
| I/dalvikvm(  289): SIGUSR1 forcing GC and HPROF dump
 | |
| I/dalvikvm(  289): hprof: dumping VM heap to "/data/misc/heap-dump-tm1240861355-pid289.hprof-hptemp".
 | |
| I/dalvikvm(  289): hprof: dumping heap strings to "/data/misc/heap-dump-tm1240861355-pid289.hprof".
 | |
| I/dalvikvm(  289): hprof: heap dump completed, temp file removed
 | |
| </pre></blockquote>
 | |
| 
 | |
| </p><p>
 | |
| Summary: as above, use <code>mkdir</code> and <code>chmod</code>
 | |
| to ensure the directory exists and is writable by your application.
 | |
| Send the <code>SIGUSR1</code> or use the API call to initiate a dump.
 | |
| Use <code>adb pull <dump-file></code> and <code>adb shell rm
 | |
| <dump-file></code> to retrieve the file and remove it from the
 | |
| device.  The concatenation step is not needed.
 | |
| 
 | |
| </p><p>
 | |
| The new API is in the <code>android.os.Debug</code> class:
 | |
| <blockquote><pre>
 | |
| public static void dumpHprofData(String fileName) throws IOException
 | |
| </pre></blockquote>
 | |
| When called, the VM will go through the same series of steps (GC and
 | |
| generate a .hprof file), but the output will be written to a file of
 | |
| your choice, e.g. <code>/sdcard/myapp.hprof</code>.  Because you're
 | |
| initiating the action from within the app, and can write the file to
 | |
| removable storage or the app's private data area, you can do this on a
 | |
| device without root access.
 | |
| 
 | |
| 
 | |
| <h3>Android 1.6 ("Donut")</h3>
 | |
| <p>
 | |
| No real change to the way profiling works.
 | |
| However, 1.6 introduced the <code>WRITE_EXTERNAL_STORAGE</code>
 | |
| permission, which is required to write data to the SD card.  If you're
 | |
| accustomed to writing profile data to <code>/sdcard</code>, you will
 | |
| need to enable the permission in your application's manifest.
 | |
| </p>
 | |
| 
 | |
| 
 | |
| <h3>Android 2.0 ("Eclair")</h3>
 | |
| <p>
 | |
| In 2.0, features were added that allow DDMS to request a heap dump on
 | |
| demand, and automatically pull the result across.  Select your application
 | |
| and click the "dump HPROF file" button in the top left.  This always
 | |
| writes files to the SD card, so
 | |
| you must have a card inserted and the permission enabled in your application.
 | |
| </p>
 | |
| 
 | |
| 
 | |
| <h3>Android 2.2 ("Froyo")</h3>
 | |
| <p>
 | |
| DDMS heap dump requests are now streamed directly out of the VM, removing
 | |
| the external storage requirement.
 | |
| </p>
 | |
| 
 | |
| <h3>Android 2.3 ("Gingerbread")</h3>
 | |
| <p>
 | |
| The <code>kill -10</code> (<code>SIGUSR1</code>) method of generating heap
 | |
| dumps has been removed from the VM.
 | |
| </p>
 | |
| 
 | |
| <h3>Android 3.0 ("Honeycomb")</h3>
 | |
| <p>
 | |
| A new command-line tool has been added:
 | |
| </p>
 | |
| <blockquote><pre>am dumpheap <pid> <output-file-name></pre></blockquote>
 | |
| <p>
 | |
| Unlike the <code>SIGUSR1</code> approach, this does not require a rooted
 | |
| phone.  It's only necessary for the application to be debuggable (by setting
 | |
| <code>android:debuggable="true"</code> in the <code><application></code>
 | |
| element of the app manifest).  The output file is opened by "am", which
 | |
| means you can write the data to a file on <code>/sdcard</code> without
 | |
| needing the <code>WRITE_EXTERNAL_STORAGE</code> permission in your app.
 | |
| <p>
 | |
| The <code>runhat</code> shell function has been updated to use this.
 | |
| </p>
 | |
| 
 | |
| <h2>Examining the data</h2>
 | |
| <p>
 | |
| The data file format was augmented slightly from the common hprof format,
 | |
| and due to licensing restrictions the modified <code>hat</code> tool cannot
 | |
| be distributed.  A conversion tool, <code>hprof-conv</code>, can be used
 | |
| to strip the Android-specific portions from the output.  This tool was
 | |
| first included in 1.5, but will work with older versions of Android.
 | |
| </p><p>
 | |
| The converted output should work with any hprof data analyzer, including
 | |
| <code>jhat</code>, which is available for free in the Sun JDK, and
 | |
| Eclipse MAT.
 | |
| 
 | |
| <!-- say something about how to track down common problems, interesting
 | |
|      things to look for, ...? -->
 | |
| 
 | |
| </p><p>
 | |
| <address>Copyright © 2009 The Android Open Source Project</address>
 | |
| 
 | |
| </body>
 | |
| </html>
 |