How to enable native heap tracking in DDMS

Apr 25, 2012   //   by Theo   //   Blog  //  4 Comments


Background

When searching for memory leaks, we often need to examine how a process’ memory usage evolves over time. DDMS provides easy-to-use features to track Java virtual machine heap usage. However, when it comes to native heap usage, DDMS make things much harder.  This article provides a step-by-step guide to help you configure native heap tracking in DDMS.

Pre-requisites

In order to configure an Android device to track native heap usage, you will need:

  • a Mac, Linux or Windows machine with the Android SDK and ADB installed
  • an Android device with either:
    • an eng or userdebug Android build OR
    • a regular user build that has been rooted and has SuperUser installed.

Instructions on how to root specific phone models are available elsewhere on the web, and the rooting procedure usually includes the installation of SuperUser.

Device Setup

Libc Installation

All the native memory allocation functions (malloc, calloc, etc.) reside in Android’s libc library. To track heap allocations we need special versions of this library, which can log each allocation as it happens, and report back the data when required. Such special versions of libc (called libc_malloc_debug_leak.so and libc_malloc_debug_qemu.so) are included with Android, but only in the eng and userdebug Android builds. If you have either  an eng or userdebug build on your phone, then no additional steps are needed for libc installation and you can jump to the next section.

If you have a regular user build, you can add the missing libraries as follows:

  1. Download the version of CyanogenMod ROM that most closely matches your phone’s model and minor Android OS version (e.g 2.3, 4.0). If your exact model is not supported, try to find the closes match by processor type (e.g. Tegra2) and minor Android OS version. Once you have the right image, extract the libc_malloc_debug_leak.so and libc_malloc_debug_qemu.so from the system/lib directory.
  2. Copy the libc_malloc_debug_leak.so and libc_malloc_debug_qemu.so files via USB to the root of the SDCARD.
  3. Install BusyBox so you can later use the cp command to copy files.
  4. From your computer”s command prompt, log into the device shell and get a list of mounted devices using the mount command:
    adb shell
    su
    mount
    
  5. The mount output will list all mounted partitions with the corresponding devices and file system types. Examine the output and make a note of the the device and file system type for your system partition. As an example, the lines below show the system entries for two different Android phones:
    LG G2x:
    ...
    /dev/block/mmcblk0p1 /system ext3 ro,noatime,errors=continue,data=ordered 0 0
    ...
    
    Nexus S:
    ...
    /dev/block/platform/s3c-sdhci.0/by-name/system /system ext4 ro,relatime,barrier=1,data=ordered 0 0
    ...
    

    The first phone has /dev/block/mmcblk0p1 as the device and ext3 as the file system type. The second phone has /dev/block/platform/s3c-sdhci.0/by-name/system as the device and ext4 as the file system type.

  6. Using the partition device name and file system type you obtained in step 5 above, remount the system partition in read-write mode. The section below shows the remount command for the two phones above:
    LG G2x:
    mount -o remount,rw -t ext3 /dev/block/mmcblk0p1 /system
    
    Nexus S:
    mount -o remount,rw -t ext4 /dev/block/platform/s3c-sdhci.0/by-name/system /system
    
  7. Copy the two libc files from the SDCARD to the /system/lib directory:
    cp /sdcard/libc_malloc_debug_leak.so /system/lib/libc_malloc_debug_leak.so
    cp /sdcard/libc_malloc_debug_qemu.so /system/lib/libc_malloc_debug_qemu.so
    
  8. Set the proper permissions:
    chmod 0644 /system/lib/libc_malloc_debug_leak.so
    chmod 0644 /system/lib/libc_malloc_debug_qemu.so
    
  9. Reboot the phone to reset the system partition to read only.

Property Configuration

Once the device has the new libc files installed, you need to tell the system to use the new libc files for memory allocation.

  1. Set the libc.debug.malloc property to one of the supported values below, depending on your needs. If you are using a device with a rooted user build, then you must perform these commands from the device’s root prompt (use su to get root privileges, as shown below).
    adb shell
    su
    setprop libc.debug.malloc 1
    

    Supported property values:

    1  - perform leak detection
    5  - fill allocated memory to detect overruns
    10 - fill memory and add sentinels to detect overruns
    20 - use special instrumented malloc/free routines for the emulator
    
  2. Restart the application framework from the same root prompt. For this to work you must use a prompt with root privileges.
    stop
    start
    

    If the commands are successful, your device will seem to reboot 1-2 seconds after the commands were issued. However, it’s not a full reboot, and you will notice that the root prompt you opened earlier remains connected.

  3. From the same prompt used earlier, check that the property was successfully set:
    getprop
    

    The command above will display a list of custom properties, which should contain a line like the following:

    ...
    [libc.debug.malloc]: [1]
    ...
    
  4. As an additional check, issue the ls command from the device prompt. If the setup was successful, then you should see something like the following line in the device log:
    05-10 20:34:01.494: I/libc(6978): ls using MALLOC_DEBUG = 1 (leak checker)
    

Computer Setup

By default, DDMS does not display the native heap tab. To enable that tab, we must modify the DDMS configuration.

  1. Open the ddms.cfg file located at ~/.android/ddms.cfg.
  2. At the bottom of the file, add the following line:
    ...
    native=true
    
  3. Save and close the configuration file.
  4. Open the stand alone DDMS tool from the Android SDK tools folder. Make sure that no Eclipse instance is open, since only one instance of DDMS can operate at a time.
  5. Select one of the processes from the list of running processes, and in right hand side panel open the Native Heap tab. Press the Snapshot Current Native Heap Usage button and you should see a list of allocations similar to the one shown in the graphic at the top of this article.

Troubleshooting

The native tab is not populated with data.

Couple of things to check:

  • Use adb shell followed by ls /system/lib/libc* to confirm that  libc_malloc_debug_leak.so and libc_malloc_debug_qemu.so are present on the device.
  • Perform a computer restart. Also shut down the Android device and remove the battery for 20 seconds before restarting. Once that is complete, redo all the steps in the Property Configuration section. Double check that you are using the root command prompt  (adb shell followed by su) to issue all the shell commands, and that you are typing the commands correctly.
  • Make sure that after issuing the stop and start commands the device successfully resets the application framework (it should look like a reboot but without losing the adb connection).

When I issue the start command the adb connection breaks.

You are probably using the wrong versions of the libc files. Make sure that the libc files are compatible with your device’s processor and Android version. If you are using CyanogenMod to get the libc files, try to get them from the same phone model (or one with a similar processor) with the same Android OS level (2.3, 4.0, etc.)

The log shows the following error: “/system/bin/sh: Missing module /system/lib/libc_malloc_debug_leak.so required for malloc debug level 1”

You are missing the libc libraries required for debug. Please follow the steps in the Libc Installation section to correct the problem.

4 comments on “How to enable native heap tracking in DDMS

  1. kmonsoor on said:

    really a great writeup. thanks buddy

  2. hanh on said:

    In the Property Configuration part, my device’s* start-up screen hangs after “start” in step 2, although subsequent checks in steps 3 & 4 were successful.

    *I’m using the Galaxy S4 running Android 4.4.2.

    Thanks,
    Hanh

  3. Hi,
    This article really helps.
    I found the “row” (libxxx.so + method) which causes memory leak.

    However, I could not translate the address of ‘method’ to its real file name and line number.
    I searched internet and tried to use addr2line

    arm-linux-androideabi-addr2line -C -f -e obj/local/armeabi-v7a/libxxx.so

    In my case, the number of method is 755535e4
    Would you share how to set correctly for addr2line?

    Thank you
    Jack

  4. Thomas Trummer on said:

    Thirst I will thank for this great howto
    Secondly I hope you can help me with my problem.
    I have made everything you have descriped but if I call “adb shell ls” I got the following error message at the logcat output:
    “Missing module /system/lib/libc_malloc_debug_leak.so required for malloc debug level 1: dlopen failed: cannot locate symbol “min_allocation_report_limit” referenced by “libc_malloc_debug_leak.so”…”
    My phone is a Galaxy S3 with Android 4.3 so I have downloaded 10.2 CyanogenMod from this link “http://download.cyanogenmod.org/?device=i9300&type=stable”
    Have I made anything wrong or did I have the wrong version?

Leave a Reply

Your email address will not be published. Required fields are marked *

*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>