NO IMAGE

    為 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 到裝置上執行,根據出錯資訊找缺失的檔案……不過還是相當值得,利器在手啦。