天天看點

在android上使用valgrind檢測記憶體洩漏

    為 Android 開發了一個 native 程式,使用 C 語言。測試時觀察記憶體占用,發現有記憶體洩漏。之前在 Linux 下使用過 valgrind ,于是想針對 Android 平台編譯一個 Valgrind 版本,用來檢測我的 native 程式。

    我的開發環境是 Windows 7,決定使用 Cygwin 來編譯。

    Cygwin 的具體安裝不多說了,注意的是,一些開發工具必須選擇,比如 gcc 、 autoconf 、 automake 等等。

    Valgrind 最新的 release 版本是 3.9.0 ,官網下載下傳。下載下傳後解壓,閱讀源碼根目錄下的 README.android 檔案,先有個初步了解。

    使用 Cygwin 來編譯 Valgrind 和在 Linux 環境下編譯還是有一些差别。我已經編譯通過并正常使用。首先進入 Cygwin 的 shell ,然後,下面是詳細的步驟。

    (一)設定 NDK 路徑

    指令很簡單,export NDKROOT=E:/android-ndk-r8d (替換為你開發主機上的實際路徑)。

    需要注意的是,這裡的 NDKROOT 不能用 Cygwin 挂載的路徑 /cygdrive/e/xxx 這種形式,否則 configure 時檢測工具鍊是否可以生成可執行檔案時會找不到 ctrbegin_dynamic.o 及 C 庫,導緻 configure 失敗。這個花費了我将近一個小時的時間!

    (二)設定硬體型号

    export HWKIND=generic

    我設定了上面的類型,實際應用中可以和具體的目标裝置關聯起來。

    (三)設定工具鍊

    這裡和 README.android 稍有不同。具體如下:

export AR=$NDKROOT/toolchains/arm-linux-androideabi-4.4.3/prebuilt/windows/bin/arm-linux-androideabi-ar.exe
export LD=$NDKROOT/toolchains/arm-linux-androideabi-4.4.3/prebuilt/windows/bin/arm-linux-androideabi-ld.exe
export CC=$NDKROOT/toolchains/arm-linux-androideabi-4.4.3/prebuilt/windows/bin/arm-linux-androideabi-gcc.exe
           

    (四)配置( configure )

     先進入到 valgrind 源碼根目錄。

    找到 configure 檔案,做一些修改,否則 configure 會失敗。因為 configure 會檢測編譯主機核心版本,Cygwin 的 uname -r 傳回的版本不是 Linux 核心版本号,我的環境傳回是 1.7.28(0.271/5/3) 。找到 5508 行,修改成下面的樣子(在2.6.*前加入了1.7.*):

case "${kernel}" in
             1.7.*|2.6.*|3.*)
           

    這樣核心版本檢測才會通過。

    配置選項還要做一些修改,這裡和 README.android 稍有不同,我添加 LIBS 選項,修改了 --target 。具體如下:

CPPFLAGS="--sysroot=$NDKROOT/platforms/android-14/arch-arm -DANDROID_HARDWARE_$HWKIND" \
  CFLAGS="--sysroot=$NDKROOT/platforms/android-14/arch-arm"  \
  LIBS="-L$NDKROOT/platforms/android-14/arch-arm/usr/lib" \
  ./configure --prefix=/data/local/Inst --host=armv7-unknown-linux \
  --target=arm-linux-androideabi  --with-tmpdir=/sdcard
           

    (五) 編譯

    執行 make ,就這麼簡單了,我這裡通過了。

    (六)安裝

    make install ,這裡會失敗。我的錯誤資訊如下:

make[2]: Entering directory '/cygdrive/e/sources/valgrind-3.9.0/VEX'
priv/.deps/libvex_arm_linux_a-host_s390_defs.Po:1: *** 多個目标比對。 停止。
make[2]: Leaving directory '/cygdrive/e/sources/valgrind-3.9.0/VEX'
Makefile:665: recipe for target 'install-recursive' failed
make[1]: *** [install-recursive] Error 1
make[1]: Leaving directory '/cygdrive/e/sources/valgrind-3.9.0'
Makefile:990: recipe for target 'install' failed
make: *** [install] Error 2
           

    我沒有搭理它,因為我發現 valgrind 和 memcheck 已經編譯出來,決定放到目标裝置上跑跑看,一跑,成功了!

    實際上為了做記憶體檢測,需要 valgrind 、memcheck 、default.supp 、 vgpreload_core-arm-linux.so 、vgpreload_memcheck-arm-linux.so 這五個檔案, push 到裝置上即可。

    (六)運作

    像上面那樣 push 程式到裝置上,要想運作,必須設定一個環境變量 VALGRIND_LIB ,valgrind 會根據這個環境變量來查找要加載的工具,如 memcheck 等,否則會報錯,找不到檔案。

    現在可以這麼啟動目标程式了:

/data/data/valgrind/valgrind --leak-check=full --track-origins=yes --log-file=check.log  your-target-executable
           

    我們把日志輸出到 check.log 檔案中,友善檢視。

    ------------

    好啦,到現在為止, valgrind for android 已經可以使用了。

    整個過程花了我 2 個多小時,對着 Cygwin 下面的報錯,檢視 config.log ,修改指令,修改 configure ,push 到裝置上運作,根據出錯資訊找缺失的檔案……不過還是相當值得,利器在手啦。

繼續閱讀