退出U盤模式後滑動Launcher卡頓的問題分析

        最近公司的手機發現退出U盤模式後,在U盤存有圖片等內容比較多的情況下,滑動Launcher會有一段時間卡頓的現象。其實不是最近的項目纔有的問題,以前的項目就有,一直都沒有解決而已,頑疾。

       當然,是在U盤不同模式直接切換的時候出現了問題,跟負責Vold的一起分析了一下,沒有發現什麼異常的地方。測試的時候發現,U盤存儲的內容越多,出現卡頓情況的時間越長,可能與media進程有關。不管怎麼樣,media是在後臺進行數據掃描,此時耗費CPU比較多,滑動桌面佔用的CPU資源也比較大,按這樣的思路,應該是在在CPU的使用上有衝突。top了一下,media在掃描的時候佔有的CPU確實比較高,在20%~40%之間。

 1830  1  27% S    14 1230360K  53056K  bg u0_a30   android.process.media

找負責media的同事一起看看吧!

        media的同事說,所有的Android手機都一樣,在掃描的時候,CPU佔用都是這麼高,是沒法降低的,看來,media是無法解決了。但是我在對比其他廠家的機器時,卻沒有發現這個時候滑動Launcher卡頓的情況。我想,竟然覺得瓶頸在CPU上,把CPU全部設置成performance狀態,應該問題會有所改善吧?於是嘗試了一下,結果問題沒有任何的改善!

       這是什麼情況?難道不是因爲競爭CPU而導致的卡頓。問題又毫無頭緒了,人生大起大落實在是太快了。明明可以看到Launcer和media佔用的CPU都很高,確不是因爲CPU的瓶頸導致的問題!!!雖然把CPU設置成performance後,CPU的使用率是降低了,但卡頓現象還是存在的。再用Systrace看了一下,沒有發現蛛絲馬跡。難道Launcher有問題?找Launcher同事一起分析!

      跟Launcher同事一起看了一下Systrace文件,也沒有發現問題。當時討論的時候,我便瞎想起來,如果不是CPU引起的問題,那是不是因爲內存引起的呢?畢竟media跟Launcher競爭的資源並不多,除了CPU,也就只有內存影響比較大了。於是我們在剛開始滑動Launcher跟Launcher停止的時候都添加了log,過濾dalvikvm和添加的log後,發現,在卡頓的時候,都有GC的操作。在media掃描的時候,media不僅自己進行了大量的GC,還引起了system_server的GC:

02-11 10:35:30.008 D/dalvikvm(13845): GC_EXPLICIT freed 89K, 36% free 93009K/143540K, paused 2ms+6ms, total 50ms

02-11 10:35:30.058 D/dalvikvm(14440): GC_EXPLICIT freed 592K, 23% free 26298K/34112K, paused 2ms+5ms, total 30ms

02-11 10:35:30.388 D/dalvikvm(13845): GC_EXPLICIT freed 92K, 36% free 93009K/143540K, paused 4ms+10ms, total 91ms

02-11 10:35:30.728 D/dalvikvm(13845): GC_EXPLICIT freed 105K, 36% free 93011K/143540K, paused 3ms+8ms, total 65ms

02-11 10:35:30.768 D/dalvikvm(14440): GC_EXPLICIT freed 597K, 23% free 26298K/34112K, paused 1ms+4ms, total 19ms

02-11 10:35:30.968 D/dalvikvm(13845): GC_EXPLICIT freed 92K, 36% free 93009K/143540K, paused 2ms+9ms, total 70ms

02-11 10:35:31.238 D/dalvikvm(13845): GC_EXPLICIT freed 92K, 36% free 93009K/143540K, paused 3ms+7ms, total 70ms

02-11 10:35:31.288 D/dalvikvm(14440): GC_EXPLICIT freed 600K, 23% free 26299K/34112K, paused 1ms+4ms, total 28ms

02-11 10:35:31.568 D/dalvikvm(13845): GC_EXPLICIT freed 183K, 36% free 93025K/143540K, paused 3ms+6ms, total 77ms

02-11 10:35:31.828 D/dalvikvm(13845): GC_EXPLICIT freed 102K, 36% free 93014K/143540K, paused 5ms+6ms, total 65ms

02-11 10:35:31.868 D/dalvikvm(14440): GC_EXPLICIT freed 600K, 23% free 26299K/34112K, paused 1ms+3ms, total 25ms

02-11 10:35:32.128 D/dalvikvm(13845): GC_EXPLICIT freed 107K, 36% free 93015K/143540K, paused 5ms+8ms, total 83ms

02-11 10:35:32.418 D/dalvikvm(13845): GC_EXPLICIT freed 91K, 36% free 93013K/143540K, paused 4ms+10ms, total 89ms

02-11 10:35:32.458 D/dalvikvm(14440): GC_EXPLICIT freed 609K, 23% free 26299K/34112K, paused 1ms+3ms, total 21ms

02-11 10:35:32.658 D/dalvikvm(13845): GC_EXPLICIT freed 104K, 36% free 93015K/143540K, paused 2ms+7ms, total 56ms

02-11 10:35:32.878 D/dalvikvm(13845): GC_EXPLICIT freed 91K, 36% free 93014K/143540K, paused 3ms+8ms, total 66ms

13845和14440分別是system_server跟media進程:

system    13845 13799 1459616 224164 ffffffff 401034ac S system_server

u0_a30    14440 13799 1235768 53220 ffffffff 401045b0 S android.process.media

當然,media的GC我們可以不用關心,我們關心的是system_server進程的GC,因爲system_server的GC是引起Launcher卡頓的原因。這個時候,Launcher的同事說,看來我的猜想是對的,我可以當什麼家了!!!偷笑

      於是乎又跑負責media的同事那,一起看了一會log,無法定位到爲什麼media引起了system_server進行了GC。我讓media的同事先看看,自己也回到座位上看看。
      我看GC的原因都是GC_EXPLICIT引起的,也就是system_server某個地方主動調用進行了GC操作引起的。我在Heap.cpp裏面在GC_EX的地方把堆棧打出來:
02-11 10:52:43.951 D/dalvikvm( 1048): #00  pc 0002bbd0  /system/lib/libdvm.so
02-11 10:52:43.951 D/dalvikvm( 1048): #01  pc 0002c874  /system/lib/libdvm.so (dvmCollectGarbageInternal(GcSpec const*)+2132)
02-11 10:52:43.951 D/dalvikvm( 1048): #02  pc 000586fe  /system/lib/libdvm.so (dvmCollectGarbage()+29)
02-11 10:52:43.951 D/dalvikvm( 1048): #03  pc 00029860  /system/lib/libdvm.so
02-11 10:52:43.951 D/dalvikvm( 1048): #04  pc 0002e50c  /system/lib/libdvm.so (dvmInterpret(Thread*, Method const*, JValue*)+184)
02-11 10:52:43.951 D/dalvikvm( 1048): #05  pc 000630d8  /system/lib/libdvm.so (dvmCallMethodV(Thread*, Method const*, Object*, bool, JValue*, std::__va_list)+291)
02-11 10:52:43.951 D/dalvikvm( 1048): #06  pc 0004cc62  /system/lib/libdvm.so
02-11 10:52:43.951 D/dalvikvm( 1048): #07  pc 0004f1d0  /system/lib/libandroid_runtime.so
02-11 10:52:43.951 D/dalvikvm( 1048): #08  pc 0007391e  /system/lib/libandroid_runtime.so (android::javaObjectForIBinder(_JNIEnv*, android::sp<android::IBinder> const&)+273)
02-11 10:52:43.951 D/dalvikvm( 1048): #09  pc 0006c2ee  /system/lib/libandroid_runtime.so
02-11 10:52:43.951 D/dalvikvm( 1048): #10  pc 000203cc  /system/lib/libdvm.so (dvmPlatformInvoke+112)
02-11 10:52:43.951 D/dalvikvm( 1048): #11  pc 0005107e  /system/lib/libdvm.so (dvmCallJNIMethod(unsigned int const*, JValue*, Method const*, Thread*)+397)
02-11 10:52:43.951 D/dalvikvm( 1048): #12  pc 00029860  /system/lib/libdvm.so
02-11 10:52:43.951 D/dalvikvm( 1048): #13  pc 0002e50c  /system/lib/libdvm.so (dvmInterpret(Thread*, Method const*, JValue*)+184)
02-11 10:52:43.951 D/dalvikvm( 1048): #14  pc 000630d8  /system/lib/libdvm.so (dvmCallMethodV(Thread*, Method const*, Object*, bool, JValue*, std::__va_list)+291)
02-11 10:52:43.961 D/dalvikvm( 1048): #15  pc 0004fd2c  /system/lib/libdvm.so
02-11 10:52:43.961 D/dalvikvm( 1048): #16  pc 0006df0c  /system/lib/libandroid_runtime.so
02-11 10:52:43.961 D/dalvikvm( 1048): #17  pc 00072c56  /system/lib/libandroid_runtime.so
02-11 10:52:43.961 D/dalvikvm( 1048): #18  pc 00018182  /system/lib/libbinder.so (android::BBinder::transact(unsigned int, android::Parcel const&, android::Parcel*, unsigned int)+57)
02-11 10:52:43.961 D/dalvikvm( 1048): #19  pc 0001bdb2  /system/lib/libbinder.so (android::IPCThreadState::executeCommand(int)+505)
02-11 10:52:43.961 D/dalvikvm( 1048): #20  pc 0001c1c2  /system/lib/libbinder.so (android::IPCThreadState::joinThreadPool(bool)+181)
02-11 10:52:43.961 D/dalvikvm( 1048): #21  pc 000200f4  /system/lib/libbinder.so
02-11 10:52:43.961 D/dalvikvm( 1048): #22  pc 00011a8a  /system/lib/libutils.so (android::Thread::_threadLoop(void*)+213)
02-11 10:52:43.961 D/dalvikvm( 1048): #23  pc 0004f16a  /system/lib/libandroid_runtime.so (android::AndroidRuntime::javaThreadShell(void*)+65)
02-11 10:52:43.961 D/dalvikvm( 1048): #24  pc 0001157e  /system/lib/libutils.so
02-11 10:52:43.961 D/dalvikvm( 1048): #25  pc 0000cb60  /system/lib/libc.so (__thread_entry+72)
02-11 10:52:43.961 D/dalvikvm( 1048): #26  pc 0000ccdc  /system/lib/libc.so (pthread_create+208)

只有binder通信在native的標準流程堆棧信息,沒有我想要的比如從java層調用的System.gc這樣的操作的地方,無法定位那個地方主動調用了GC操作而引起卡頓,看來打印堆棧在不同的thread裏面是沒有多大的意義。

         爲了更好的分析問題,我又抓了一個systrace看了一下,發現Launcher在繪圖的時候,system_server確實有GC操作,導致有點時候繪製一幀花費了很長的時間,如下面的這幀:


上面是system_server GC(explicit),下面是Launcher進程,system_server進程的GC導致Launcher繪圖的時候sleep了,導致卡頓。雖然引起卡頓的原因是知道了,但是沒有定位出system_server哪個地方主動調用的GC操作導致卡頓了?爲什麼media會引起這樣的操作?從系統的角度來說,能定位出在system_server那塊代碼導致GC操作是最好不過的,那樣可以讓media的同事知道自己進行了什麼操作而導致問題,好讓media進行相應的優化。個人觀點,也可以自己不管了,扔給media去折騰吧!問題很明確是他們引起的,但我還是很想知道是什麼原因,好奇害死貓!

       既然知道是system_server的問題,而且還知道system_server主動調用了java層的像System.gc這樣的接口引起的問題,那此時用traceview看看。於是抓了個traceview看了一下,讓我大吃一驚:

          
啓動了那邊多的bind進程,而且每個都是跑一下就結束了。能看到有明顯的GC操作,就是圖中紫色的部分:


從函數的調用流程繼續往上走,可以看到:


從trace能看到,在linkToDeath跟nativeReadStrongBinder時,引起了BinderInternal forceGC操作,從而導致卡頓的情況。

      把trace給media的同事看了一下,跟蹤代碼發現,在掃描的時候使用的帶notify的uri,導致system_server GC了!難怪會導致system_server有那麼多的binder通信操作!
      
     看來做系統的就是跑腿的,一會跑Launcher那看看,一會跑media那看看,一會看Vold那看看,誰都不知道是誰的問題,誰也不承認是自己的問題,而且自己又各種不懂,一不小心就被坑了!只有自己慢慢折騰,找到證據了後纔好辦呀!隨便一個問題,都要花費至少幾天的時間去分析,能解決最好,很多是最後完全不知道什麼原因導致的,從這個角度來說,應用是多麼的happy呀!


發佈了54 篇原創文章 · 獲贊 43 · 訪問量 37萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章