當前位置:
首頁 > 最新 > android native 代碼內存泄露 定位方案

android native 代碼內存泄露 定位方案

android native 代碼內存泄露 定位方案

java代碼的內存定位,暫時我們先不關注。此篇文章,主要圍繞c c++代碼的內存泄露。

歡迎留言,交流您所使用的內存泄露定位方案。

c c++代碼,由於其特殊性質,沒有虛擬機概念,內存則直接是由用戶管理,比如申請,釋放,都是需要用戶主動去觸發,如果用戶出現使用了申請,但是用完之後,沒有調用釋放,則會引起內存泄露。這種叫真正意義的內存泄露,只有重啟機子,才能恢復。

相對而已java端的內存泄露,指的是一個應用長期運行,導致相互引用,無法釋放,GC沒法回收,引起的有效內存越來越小,我們將此現象叫做,內存泄露,通過關閉此應用,重新打開即可恢復內存。因此看來,java內存泄露和c c ++ 的 還是有本質區別的。

java本身的虛擬機裡面會關注對象的申請,釋放,這些不需要用戶直接注,java虛擬機通過管理機制,將調用c c++裡面真正的malloc free 方法,封裝起來,將java對象的生命周期和malloc free 進行關聯,則可以保證在對象不使用的時候,內存緊張時,釋放掉不再被引用的對象,GC回收就是在做這件事請。

回到我們這節的主要內容,如何定位我們的c c++的內存泄露。

00

我們查看代碼,發現申請內存的代碼位置,在/bionic/libc/裡面,此庫生成出來有 libc.so libstdc++.so (手機的system/lib/裡面)我們看到這裡有個目錄/bionic/libc/malloc_debug/ ,這裡便是我們的malloc的調試源碼

按照這裡的文檔講解 (有個重點,必須是調試版本,因為需要lib_malloc_debug.so 庫的存在)

/bionic/libc/bionic/malloc_common.cpp 修改

static void malloc_init_impl(libc_globals* globals) 方法,將前面的一些判斷刪掉

然後在/bionic/libc目錄 mmm單獨編譯此模塊出來即可

adb shell 加入一些參數 (沒去較真,是否需要這個)

echo "libc.debug.malloc.program=app_process">> /system/build.prop

echo "libc.debug.malloc.options=backtrace" >> /system/build.prop

echo "libc.debug.malloc.env_enabled=1" >> /system/build.prop

echo "libc.debug.malloc=1" >> /system/build.prop

將我們編譯出來的libc.so libstdc++.so 放入手機

adb remount

adb push xxxxxx/system/lib/libc.so /system/lib

adb push xxxxxx/system/lib/libstdc++.so /system/lib

adb reboot

然後我們重啟手機,運行我們的測試demo,這裡為jnidemo

我們如何來驗證是否成功的debug malloc呢?

mt:/ # ps grep jnidemo

u0_a155 13112 343 821920 45124 SyS_epoll_ a695c8a8 S com.example.jnidemo

mt:/ #cat /proc/13112/maps grep malloc_debug

a718a000-a71ae000 r-xp 00000000 103:08 1400 /system/lib/libc_malloc_debug.so

a71af000-a71b0000 r--p 00024000 103:08 1400 /system/lib/libc_malloc_debug.so

a71b0000-a71b1000 rw-p 00025000 103:08 1400 /system/lib/libc_malloc_debug.so

mt:/ #

如果出現了這個/system/lib/libc_malloc_debug.so 則說明內存檢測調試成功了。

我們繼續來操作,找到我們電腦home目錄下的隱藏文件

/home/user/.android

在裡面的ddms.cfg文件下加入一行

native=true

加入這句之後,我們的eclipse的獨立ddms則會出現native heap顯示。

找到eclipse的sdk目錄下的/sdk/tools 裡面的ddms打開。(記得要關閉其他佔用adb的埠進程)

選擇我們的進程,然後右側選擇native heap ,點擊snapshot current native Heap usage,則會顯示出來當前進程申請的c內存信息。

我們通過這個,可以看到某個庫的某個位置申請了多大空間,然後我們多次操作,對比申請的空間,從而找到我們的內存泄露點。

01

我們這裡演示下如何找到對應的申請空間代碼位置:

從上面的圖可以看到libtest_jni.so的位置,方法位置8cf84c54 申請大小為100

於是我們需要找下8cf84c54 具體指的哪個方法,具體操作為:

使用cat /proc/pid/maps grep libtest_jni.so

看到8cf84c54 落在這裡的地址為8cf84000 - 8cf87000 中間,再看後面的r-xp 這裡有執行位。p私有位

於是我們計算8cf84c54(代碼的具體位置) -8cf84000(so的載入起始位置) =0xc54(so庫中對應方法的地址)

我們使用addr2line找到這個地址的代碼,這裡可以看到是XXXXXXXtest_jni.c 的13行,具體為,還是這個圖:

找到代碼:

我們這裡看到 malloc 申請的大小為 100位元組 代碼位置為13行,我們一直在申請,沒有釋放過,如上驗證了c c++ 內存問題,可以通過此方案進行調試,定位內存泄露問題。

02

綜上演示了一次查找,定位c代碼申請空間的位置代碼,如果發現某個過程的meminfo信息出來的native heap一直增大,我們則可以使用這個調試手段,進行定位,一般盡量定位在跟自己app關聯比較大的方法裡面。

這裡有個小問題,按照ddms這個工具的本身意圖,當我們配置好addr2line之後,配置好符號查找位置後,應該自動會解析成符號,而不是地址。但是這裡老是提示addr2line工具找不到,很是崩潰,無語,所以才有了上面的手動解析地址到方法的手段。

不過話說回來,這樣子不是更學到了內容,還是值得高興的事情。

一些參考文檔:

java內存泄露

LeakCanary

native內存泄露

喜歡這篇文章嗎?立刻分享出去讓更多人知道吧!

本站內容充實豐富,博大精深,小編精選每日熱門資訊,隨時更新,點擊「搶先收到最新資訊」瀏覽吧!


請您繼續閱讀更多來自 代碼GG之家 的精彩文章:

TAG:代碼GG之家 |

您可能感興趣

LeakCanary Android中內存泄露
FB及Cambridge Analytica因用戶數據泄露事件面臨訴訟
macOS版Microsoft Edge官方下載提前泄露
Google Pixel Slate Chromebook二合一平板泄露
AMD 7nm Radeon Instinct顯卡3Dmark泄露
運行Android Go!諾基亞Nokia 1 Plus泄露
疑似復聯4副標題泄露《Avengers Disassembled》——復仇者解散
蘋果新款Beats Powerbeats無線耳機圖片泄露,與AirPods類似
微軟Chromium版Edge瀏覽器Windows 10/macOS版Beta泄露下載
頭條:Comcast Xfinity網站API存在數據泄露隱患
標誌性Logo 加持!Patta x Air Jordan聯名新動向泄露!
Nike x Undercover 19年聯名泄露!「Waffle Racer」 系列公開
聯名傳聞泄露!Supreme x Timberland 或將下周發售
Intel十代酷睿信息泄露,10nm Ice Lake和14nm Comet Lake齊登場
再度合作!Off-White X Chrome Hearts 聯名褲泄露
為防手機信息泄露,Android 9.0新加「Lockdown」隱藏功能
Tiffany發布SOLO曲「Remember Me」 稱對泄露事件很傷心
「可放進口袋的Surface」,微軟文件泄露Andromeda真身
隱藏款公布!Supreme 夏款Photo tee泄露
用戶數據泄露三連彈:Facebook、安德瑪&Panera Bread