日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > Android >内容正文

Android

Android Koom 处理 app 的OOM 一些系列问题(java /native/thread leak)

發布時間:2024/1/18 Android 35 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Android Koom 处理 app 的OOM 一些系列问题(java /native/thread leak) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

本篇文檔是基于快手團隊的Koom 2.2.0 的tag 版本的使用介紹。

前期工作

VERSION_NAME=2.2.0// 引入koom 的靜態庫,這里版本2.2.0implementation "com.kuaishou.koom:koom-native-leak-static:${VERSION_NAME}"implementation "com.kuaishou.koom:koom-java-leak-static:${VERSION_NAME}"implementation "com.kuaishou.koom:koom-thread-leak-static:${VERSION_NAME}"implementation "com.kuaishou.koom:xhook-static:${VERSION_NAME}"

使用快手發布koom 的靜態庫,通過源碼編譯,可能遇到一些問題,編譯不通過。
更多信息,請閱讀快手 KOOM 詳細文檔

1.JavaLeak

1.1 koom輸出java 泄漏的json 信息

該json中包含:

  • runningInfo: app 當前進程信息,包含線程數、fd 數據等關鍵信息

  • gcPaths: 觸發gc的對象的調用鏈

  • leakObjects:泄漏對象

  • classInfos:類信息

先來看下,leakObjects:

[ { "className":"android.graphics.Bitmap", "extDetail":"1920 x 1080", "objectId":"327801464", "size":"2073600" }, { "className":"int[]", "objectId":"1972002816", "size":"455869" }, { "className":"byte[]", "objectId":"1973350400", "size":"524301" }, { "className":"char[]", "objectId":"1974407184", "size":"1048589" } ]

從上面看,可知有bimap 和數組存在泄漏,但無更詳細信息。

接下來看下gcPaths中一部分信息:

{ "gcRoot":"Local variable in native code", "instanceCount":1, "leakReason":"Bitmap Size Over Threshold, 1920x1080", "path":[ { "declaredClass":"java.lang.ClassLoader", "reference":"dalvik.system.PathClassLoader.runtimeInternalObjects", "referenceType":"INSTANCE_FIELD" }, { "declaredClass":"java.lang.Object[]", "reference":"java.lang.Object[]", "referenceType":"ARRAY_ENTRY" }, { "declaredClass":"com.kwai.koom.demo.javaleak.test.LeakMaker", "reference":"com.kwai.koom.demo.javaleak.test.LeakMaker.leakMakerList", "referenceType":"STATIC_FIELD" }, { "declaredClass":"java.util.ArrayList", "reference":"java.util.ArrayList.elementData", "referenceType":"INSTANCE_FIELD" }, { "declaredClass":"java.lang.Object[]", "reference":"java.lang.Object[]", "referenceType":"ARRAY_ENTRY" }, { "declaredClass":"com.kwai.koom.demo.javaleak.test.LeakMaker", "reference":"com.kwai.koom.demo.javaleak.test.BitmapLeakMaker.uselessObjectList", "referenceType":"INSTANCE_FIELD" }, { "declaredClass":"java.util.ArrayList", "reference":"java.util.ArrayList.elementData", "referenceType":"INSTANCE_FIELD" }, { "declaredClass":"java.lang.Object[]", "reference":"java.lang.Object[]", "referenceType":"ARRAY_ENTRY" }, { "reference":"android.graphics.Bitmap", "referenceType":"instance" } ], "signature":"38ba5ba71b7599737372f965417abcf2765dbb2a" }

從gc 調用鏈看出,bitmap 被LeakMaker持有,LeakMaker 被BitmapLeakMaker持有,BitmapLeakMaker被LeakMaker 中靜態leakMakerList持有,導致bitmap 一直無法被釋放。

接下來看下runningInfo 的部分信息:

{ "buildModel":"PCLM50", "currentPage":"javaleak.JavaLeakTestActivity", "deviceMemAvaliable":"3643.6367", "deviceMemTotal":"7398.6797", "dumpReason":"reason_thread_oom", "fdCount":"138", "filterInstanceTime":"1.837", "findGCPathTime":"16.967", "jvmMax":"384.0", "jvmUsed":"6.4137344", "manufacture":"OPPO", "nowTime":"2022-08-17_15-29-50_432", "pss":"125.66699mb", "rss":"161.82812mb", "sdkInt":"31", "threadCount":"725" }

從上面信息,可知 線程是725個,fd 是138個,當前頁面是JavaLeakTestActivity等關鍵信息。

1.2 studio 解析hprof 文件

接下來,通過studio 解析下koom 生成的泄漏hprof 文件(sdcard/android/data/包名/files/performance/oom/memory/hrof-aly 目錄下)。

先查看下UI(framgent/activity)泄漏:

接下來看下,json 文件中bitmap 泄漏的情況:

更多hprof 文件解讀,自行百度。

2.NativeLeak:

2.1查看logcat 中輸出的native 泄漏的日志

2022-08-09 11:21:21.987 15584-15696/com.kwai.koom.demo I/NativeLeakTestActivity: Activity: com.kwai.koom.demo.nativeleak.NativeLeakTestActivity@36fb614//.......LeakSize: 24 ByteLeakThread: .kwai.koom.demoBacktrace:#0 pc 0x1d9c libnative-leak-test.so#1 pc 0x190c libnative-leak-test.so#2 pc 0xda278 libc.so#3 pc 0x7a448 libc.so

2.2 借用android ndk 工具(ndk-stack或者addr21line )來定位代碼位置。

執行addr2line的相關命令:

從上面可以看出native-leak-test.cpp 文件中93行:

static NOINLINE void TestContainerLeak() {std::vector<std::string *> str_vector(NR_TEST_CASE);for (int i = 0; i < NR_TEST_CASE; i++) {str_vector[i] = new std::string("test_leak_container");} }

c++ 與java 是很大不同,沒有gc 垃圾回收機制,在c++ 中 聽new 開辟的內存,必須手動delete 刪除。從上面代碼可見,通過new 創建了string 指針后,執行完TestContainerLeak()后并沒有delete刪除 該內存,因此造成native 泄漏。

3.ThreadLeakMonitor使用

3.1了解下Koom中線程泄漏的案例

先來解讀下Koom中線程泄漏案例的代碼:

static NOINLINE void TestThreadLeak(int64_t delay) {//這里使用的是c++ thread,使用lamba表達式方式來創建線程,在c++ 函數也是指針。std::thread test_thread([](int64_t delay) {//設置線程名稱為test_threadpthread_setname_np(pthread_self(), "test_thread");LOGI("test_thread run");// 聲明線程指針std::thread *test_thread_1;std::thread *test_thread_2;test_thread_1 = new std::thread([]() {pthread_setname_np(pthread_self(), "test_thread_1");LOGI("test_thread_1 run");});test_thread_2 = new std::thread([]() {pthread_setname_np(pthread_self(), "test_thread_2");LOGI("test_thread_2 run");});// 沉睡delay 秒時間,再調用 上面線程的detach()和join()std::this_thread::sleep_for(std::chrono::milliseconds(delay));test_thread_1->detach();LOGI("test_thread_1 detach");test_thread_2->join();LOGI("test_thread_2 join");}, delay);test_thread.detach(); }

簡單來說,創建一個名為test_thread的線程,在其內部開啟兩個線程test_thread1和test_thread2 ,沉睡指定時間后,再調用它兩的detach()和join()。

接下來,看下實際的效果:

3.2 查看線程泄漏的日志

當點擊測試案例,線程test_thread 開啟線程test_thread2和test_thread_1, 沉睡10秒后再調用它兩的join()或者detach()。
先是在logcat中輸出一下日志:

2022-08-09 09:57:13.334 13961-26723/com.kwai.koom.demo I/ThreadLeakTest: test_thread run 2022-08-09 09:57:13.335 13961-26726/com.kwai.koom.demo I/ThreadLeakTest: test_thread_2 run 2022-08-09 09:57:13.335 13961-26724/com.kwai.koom.demo I/ThreadLeakTest: test_thread_1 run

監控thread 沒有執行join()或者detach()方法下,執行了pthread_exit,則記錄下泄露線程信息。
2022-08-09 09:57:13到2022-08-09 09:57:18的間隔時間是5秒,剛好是enableThreadLeakCheck(2 * 1000L, 5 * 1000L)中的泄漏時間,超過這個時間,就會上報線程泄漏信息。更多詳細日志如下所示:

2022-08-09 09:57:18.538 13961-14017/com.kwai.koom.demo I/ThreadLeakTest: tid: 26726createTime: 284943128292812 BytestartTime: 284943128354687endTime: 284943128382916name: test_thread_2createCallStack:#00 pc 0000000000002084 /data/app/~~UA5bVzbMO-QDKhKIgEGpxg==/com.kwai.koom.demo-Fnd4kAPgIstzWnyszO4chg==/lib/arm64/libnative-leak-test.so (BuildId: b3e2c22d2f281ecd24ed2bdd07577439)#01 pc 00000000000da278 /apex/com.android.runtime/lib64/bionic/libc.so (__pthread_start(void*)+64) (BuildId: 1ca28d785d6567d2b225cf978ef04de5)#02 pc 000000000007a448 /apex/com.android.runtime/lib64/bionic/libc.so (__start_thread+64) (BuildId: 1ca28d785d6567d2b225cf978ef04de5) 2022-08-09 09:57:18.538 13961-14017/com.kwai.koom.demo I/ThreadLeakTest: tid: 26724createTime: 284943128217864 BytestartTime: 284943128528853endTime: 284943128671353name: test_thread_1createCallStack:#00 pc 000000000000203c /data/app/~~UA5bVzbMO-QDKhKIgEGpxg==/com.kwai.koom.demo-Fnd4kAPgIstzWnyszO4chg==/lib/arm64/libnative-leak-test.so (BuildId: b3e2c22d2f281ecd24ed2bdd07577439)#01 pc 00000000000da278 /apex/com.android.runtime/lib64/bionic/libc.so (__pthread_start(void*)+64) (BuildId: 1ca28d785d6567d2b225cf978ef04de5)#02 pc 000000000007a448 /apex/com.android.runtime/lib64/bionic/libc.so (__start_thread+64) (BuildId: 1ca28d785d6567d2b225cf978ef04de5)

當然Koom 的線程監控并不影響自身線程的邏輯,2022-08-09 09:57:13到2022-08-09 09:57:23,期間剛好沉睡10秒后,會再調用它兩的join()或者detach(),以下日志也剛好驗證。

2022-08-09 09:57:23.335 13961-26723/com.kwai.koom.demo I/ThreadLeakTest: test_thread_1 detach 2022-08-09 09:57:23.335 13961-26723/com.kwai.koom.demo I/ThreadLeakTest: test_thread_2 join。

總結

以上是生活随笔為你收集整理的Android Koom 处理 app 的OOM 一些系列问题(java /native/thread leak)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。