版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報或認(rèn)領(lǐng)
文檔簡介
1、Android系統(tǒng)穩(wěn)定性-ANR1.2如何分析ANR問題引起ANR問題的根本原因,總的來說可以歸納為兩類:應(yīng)用進(jìn)程自身引起的,例如:主線程阻塞、掛起、死循環(huán)應(yīng)用進(jìn)程的其他線程的CPU占用率高,使得主線程無法搶占到CPU寸間片其他進(jìn)程間接引起的,例如:當(dāng)前應(yīng)用進(jìn)程進(jìn)行進(jìn)程間通信請求其他進(jìn)程,其他進(jìn)程的操作長時間沒有反饋其他進(jìn)程的CPU占用率高,使得當(dāng)前應(yīng)用進(jìn)程無法搶占到CPU寸間片分析ANR問題時,以上述可能的幾種原因?yàn)榫€索,通過分析各種日志信息,大多數(shù)情況下你就可以很容易找到問題所在了。注意:確實(shí)有一些ANR問題很難調(diào)查清楚,因?yàn)檎麄€系統(tǒng)不穩(wěn)定的因素很多,例如LinuxKernel本身的bug
2、引起的內(nèi)存碎片過多、硬件損壞等。這類比較底層的原因引起的ANR、可題往往無從查起,并且這根本不是應(yīng)用程序的問題,浪費(fèi)了應(yīng)用開發(fā)人員很多時間,如果你從事過整個系統(tǒng)的開發(fā)和維護(hù)工作的話會深有體會。所以我不能保證了解了本章的所有內(nèi)容后能夠解決一切ANR、可題,如果出現(xiàn)了很疑難的ANR、可題,我建議最好去和做驅(qū)動和內(nèi)核的朋友聊聊,或者,如果問題只是個十萬分之一的偶然現(xiàn)象,不影響程序的正常運(yùn)行,我倒是建議不去理它。1.2.1分析ANR勺利器Android會在ANR生時輸出很多有用的信息幫助分析問題原因,我們先來看一下ANR勺異常信息,使用logcat命令查看會得到類似如下的log:/WindowMana
3、ger所在的進(jìn)程是system_server,進(jìn)程號是127I/WindowManager(127):Inputeventdispatchingtimedoutsendingtocom.example.anrdemo/com.example.anrdemo.ANRActivity/system_server進(jìn)程中的ActivityManagerService請求kernel向5033進(jìn)程發(fā)送SIGNAL_QUIT肯求你可以在shell中使用命令達(dá)到相同的目的:adbshellkill-35033/和其他的Java虛擬機(jī)一樣,SIGNAL_QUI如是Dalvik內(nèi)部支持的功能之I/Process
4、(127):Sendingsignal.PID:5033SIG:3/5033進(jìn)程的虛擬機(jī)實(shí)例接收到SIGNAL_QUIT信號后會將進(jìn)程中各個線程的函數(shù)堆棧信息輸出到traces.txt文件中/發(fā)生ANR的進(jìn)程正常情況下會第一個輸出I/dalvikvm(5033):threadid=4:reactingtosignal3I/dalvikvm(5033):Wrotestacktracesto'/data/anr/traces.txt'/另外還有其他一些進(jìn)程/隨后會輸出CPUS用情況E/ActivityManager(127):ANRincom.example.anrdemo(com
5、.example.anrdemo/.ANRActivity)/Reason表示導(dǎo)致ANR'可題的直接原因E/ActivityManager(127):Reason:keyDispatchingTimedOutE/ActivityManager(127):Load:3.85/3.41/3.16/請注意ago,表示ANR生之前的一段時間內(nèi)的CPU使用率,并不是某一時刻的值E/ActivityManager(127):CPUusagefrom26835msto3662msagowith99%awake:E/ActivityManager(127):9.4%98/mediaserver:9.4
6、%user+0%kernelE/ActivityManager(127):8.9%127/system_server:6.9%user+2%kernel/faults:1823minor.E/ActivityManager(127):+0%5033/com.example.anrdemo:0%user+0%kernelE/ActivityManager(127):39%TOTAL:32%user+6.1%kernel/這里是later,表示ANR®生之后E/ActivityManager(127):CPUusagefrom601msto1132mslaterwith99%awake:
7、E/ActivityManager(127):10%127/system_server:1.7%user+8.9%kernel/faults:5minorE/ActivityManager(127):10%163/InputDispatcher:1.7%user+8.9%kernelE/ActivityManager(127):1.7%127/system_server:1.7%user+0%kernelE/ActivityManager(127):1.7%135/SurfaceFlinger:0%user+1.7%kernelE/ActivityManager(127):1.7%2814/B
8、inderThread#:1.7%user+0%kernelE/ActivityManager(127):37%TOTAL:27%user+9.2%kernel從log中能夠知道,發(fā)生ANR寸Android為我們提供了兩種“利器”:traces文件和CPU®用率。以上做了簡單注釋,不過稍后再詳細(xì)分析它們。1.2.2ANR信息是如何輸出的我們再來看看這些log是怎樣被輸出的,這很重要,知其然,也要知其所以然。代碼在ActivityManagerService類中,找到它的appNotResponding函數(shù)。finalvoidappNotResponding(ProcessRecord
9、app,ActivityRecordactivity,ActivityRecordparent,finalStringannotation)/firstPids和lastPids兩個集合存放那些將會在traces中輸出信息的進(jìn)程的進(jìn)程號ArrayList<Integer>firstPids=newArrayList<Integer>(5);SparseArray<Boolean>lastPids=newSparseArray<Boolean>(20);/mController是IActivityController接口的實(shí)例,是為Monkey測試
10、程序預(yù)留的,默認(rèn)為nullif(mController!=null).longanrTime=SystemClock.uptimeMillis();if(MONITOR_CPU_USAGE)(updateCpuStatsNow();/更新CPUf£用率synchronized(this)(/一些特定條件下會忽略ANRif(mShuttingDown)(Slog.i(TAG,"DuringshutdownskippingANR:"+app+""+annotation);return;elseif(app.notResponding)(Slog.i
11、(TAG,"SkippingduplicateANR:"+app+""+annotation);return;elseif(app.crashing)(Slog.i(TAG,"CrashingappskippingANR:"+app+""+annotation);return;/使用一個標(biāo)志變量避免同一個應(yīng)用在沒有處理完時重復(fù)輸出logapp.notResponding=true;./當(dāng)前發(fā)生ANR的應(yīng)用進(jìn)程被第一個添加進(jìn)firstPids集合中firstPids.add(app.pid);/dumpStackTr
12、aces是輸出traces文件的函數(shù)FiletracesFile=dumpStackTraces(true,firstPids,processStats,lastPids,null);StringcpuInfo=null;if(MONITOR_CPU_USAGE)(/MONITOR_CPU_USAGE認(rèn)為trueupdateCpuStatsNow();/再次更新CPU言息synchronized(mProcessStatsThread)(輸出ANR生前一段時間內(nèi)的CPUS用率cpuInfo=mProcessStatsprintCurrentState(anrTime);info-appendl
13、processStatsgrintCurrentLoad。);infoappend(cpuInfo);輸出ANR生后一段時間內(nèi)的CPUS用率infoappend(processStatsprintCurrentState(anrTime);/將ANR信息同時輸出到DropBox中addErrorToDropBox("anr",app,cessName,activity,parent,annotation,cpuInfo,tracesFile,null);./在Android4.0中可以設(shè)置是否不顯示AN破示對話框,如果設(shè)置的話就不會顯示對話框,并且會殺掉ANR
14、®程booleanshowBackground=Settings.Secure.getInt(mContext.getContentResolver(),Settings.Secure.ANR_SHOW_BACKGROUND,0)!=0;synchronized(this)if(!showBackground&&!app.isInterestingToUserLocked()&&app.pid!=MY_PID).Process.killProcessQuiet(app.pid);return;./顯示anrH示對話框Messagemsg=Message
15、.obtain();HashMapmap=newHashMap();msg.what=SHOW_NOT_RESPONDING_MSG;msg.obj=map;map.put("app",app);if(activity!=null)(map.put("activity",activity);mHandler.sendMessage(msg);有三個關(guān)鍵點(diǎn)需要注意: 當(dāng)前發(fā)生ANR勺應(yīng)用進(jìn)程被第一個添加進(jìn)firstPids集合中,所以會第一個向traces文件中寫入信息。反過來說,traces文件中出現(xiàn)的第一個進(jìn)程正常情況下就是發(fā)生ANR勺那個進(jìn)程。不過有
16、時候會很不湊巧,發(fā)生ANR勺進(jìn)程還沒有來得及輸出trace信息,就由于某種原因退出了,所以偶爾會遇到traces文件中找不到發(fā)生ANR勺進(jìn)程信息的情況。 dumpStackTraces是輸出traces文件的函數(shù),接下來分析這個函數(shù)addErrorToDropBox函數(shù)將ANRR言息同時輸出到DropBox中,它也是個非常有用的日志存放工具,后面也會分析它的作用。publicstaticFiledumpStackTraces(booleanclearTraces,ArrayList<Integer>firstPids,ProcessStatsprocessStats,SparseA
17、rray<Boolean>lastPids,StringnativeProcs)(/系統(tǒng)屆性“dalvik.vm.stack-trace-file”用來配置trace信息輸出文件StringtracesPath=SystemProperties.get("dalvik.vm.stack-trace-file",null);if(tracesPath=null|tracesPath.length()=0)(returnnull;FiletracesFile=newFile(tracesPath);try(FiletracesDir=tracesFile.getPa
18、rentFile();if(!tracesDir.exists()tracesFile.mkdirs();/FileUtils.setPermissions是個很有用的函數(shù),設(shè)置文件屆性時經(jīng)常會用到FileUtils.setPermissions(tracesDir.getPath(),0775,-1,-1);/drwxrwxr-x/clearTraces為true,會刪除舊文件,創(chuàng)建新文件if(clearTraces&&tracesFile.exists()tracesFile.delete();tracesFile.createNewFile();FileUtils.set
19、Permissions(tracesFile.getPath(),0666,-1,-1);/-rw-rw-rw-catch(IOExceptione)(Slog.w(TAG,"UnabletoprepareANRtracesfile:"+tracesPath,e);returnnull;/一個重載函數(shù)dumpStackTraces(tracesPath,firstPids,processStats,lastPids,nativeProcs);returntracesFile;有兩個關(guān)鍵點(diǎn)需要注意: 聰明的你肯定已經(jīng)知道,之所以trace信息會輸出到“/data/anr/tr
20、aces.txt”文件中,就是系統(tǒng)屬性“dalvik.vm.stack-trace-file”設(shè)置的。你可以通過在設(shè)備的shell中使用setprop和getprop對系統(tǒng)屬性進(jìn)行設(shè)置和讀?。?getpropdalvik.vm.stack-trace-filesetpropdalvik.vm.stack-trace-file/tmp/stack-traces.txt每次發(fā)生ANR寸都會刪除舊的traces文件,重新創(chuàng)建新文件。也就是說Android只保留最后一次發(fā)生ANR寸的traces信息,那么以前的traces信息就丟失了么?稍后回答。接著來看重載的dumpStackTraces函數(shù)。pr
21、ivatestaticvoiddumpStackTraces(StringtracesPath,ArrayList<Integer>firstPids,ProcessStatsprocessStats,SparseArray<Boolean>lastPids,StringnativeProcs)/使用FileObserver監(jiān)聽?wèi)?yīng)用進(jìn)程是否已經(jīng)完成寫入traces文件的操作/Android在判斷桌面壁紙文件是否設(shè)置完成時也是用的FileObserver,很有用的類FileObserverobserver=newFileObserver(tracesPath,FileOb
22、server.CLOSE_WRITE)publicsynchronizedvoidonEvent(intevent,Stringpath)notify();./首先輸出firstPids集合中指定的進(jìn)程,這些也是對ANR問題來說最重要的進(jìn)程if(firstPids!=null)tryintnum=firstPids.size();for(inti=0;i<num;i+)synchronized(observer)/前面提到的SIGNAL_QUITProcess.sendSignal(firstPids.get(i),Process.SIGNAL_QUIT);observer.wait(2
23、00);提示:如果你在解決其他問題時也需要查看Java進(jìn)程中各個線程的函數(shù)堆棧信息,就可以使用向目標(biāo)進(jìn)程發(fā)送SIGNAL_QUIT(3)這個技巧。其實(shí)這個名稱有點(diǎn)誤導(dǎo),它并不會讓進(jìn)程真正退出。1.2.3DropBox剛才留了一個問題:Android只保留最后一次發(fā)生ANF®寸的traces信息,那么以前的traces信息就丟失了么?為了增強(qiáng)Android的異常信息收集管理能力,從2.2開始增加了DropBox功能。DropBox(簡稱D0是系統(tǒng)進(jìn)程中的一個服務(wù),在system_server進(jìn)程啟動時創(chuàng)建,并且它沒有運(yùn)行在單獨(dú)的線程中,而是運(yùn)行在system_server的Server
24、Thread線程中。我們可以將ServerThread稱作system_server的主線程,ServerThread線程除了啟動并維護(hù)各個服務(wù)外,還負(fù)責(zé)檢測一些重要的服務(wù)是否死鎖,這一點(diǎn)到后面的Watchdog部分再分析<!-Watchdog寫完后注意補(bǔ)充章節(jié)號->。DB被創(chuàng)建的代碼如下。SystemServer.javaServerThread.run()Slog.i(TAG"DropBoxService");ServiceManager.addService(Context.DROPBOX_SERVICE服務(wù)名稱為“dropbox”newDropBoxMa
25、nagerService(context,newFile("/data/system/dropbox");“/data/system/dropbox”是DB指定的文件存放位置。下面來看一下DB服務(wù)的主要功能。1.DropBoxManagerServiceDropBoxManagerService(簡稱DBMS就是DB服務(wù)的本尊,它的主要功能接口包括以下幾個函數(shù):publicvoidadd(DropBoxManager.Entryentry)DBM翳所有要添加的日志都用DropBoxManager.Entry類型的對象表示,通過add函數(shù)添加,并且直到目前為止一個Entry對
26、象對應(yīng)著一個日志文件。publicbooleanisTagEnabled(Stringtag)通過給每一個Entry設(shè)置一個tag可以標(biāo)識不同類型的日志,并且可以靈活的啟用/禁用某種類型的日志,isTagEnabled用來判斷指定類型的日志是否被啟用/禁用了,一旦禁用就不會再記錄這種類型的日志。默認(rèn)是不禁用任何類型的日志的。稍后說明如何啟用/禁用日志。publicsynchronizedDropBoxManager.EntrygetNextEntry(Stringtag,longmillis)我們可以通過getNextEntry函數(shù)獲取指定類型和指定時間點(diǎn)之后的第一條日志,要使用這個功能應(yīng)用程
27、序需要有“android.permission.READ_LOGS”的權(quán)限,并且在使用完畢返回的Entry對象后要調(diào)用其close函數(shù)確保關(guān)閉日志文件的文件描述符(如果不關(guān)閉的話可能造成進(jìn)程打開的文件描述符超過1024而崩潰,Android中限制每個進(jìn)程的文件描述符上限為1024)。DBM洗供了很多的配置項(xiàng)用來限制對磁盤的使用,通過SettingsProvider應(yīng)用程序維護(hù),數(shù)據(jù)存放在其settings.db數(shù)據(jù)庫中。這些配置項(xiàng)也都有默認(rèn)值,羅列如下:Settings.Secure.DROPBOX_AGE_SECONDS="dropbox_age_seconds"日志文件
28、保存的最長時間,默認(rèn)3天Settings.Secure.DROPBOX_MAX_FILES="dropbox_max_files"日志文件的最大數(shù)最,默認(rèn)值是1000Settings.Secure.DROPBOX_QUOTA_KB="dropbox_quota_kb"磁盤空間最大使用景Settings.Secure.DROPBOX_QUOTA_PERCENT="dropbox_quota_percent"Settings.Secure.DROPBOX_RESERVE_PERCENT="dropbox_reserve_perc
29、ent"Settings.Secure.DROPBOX_TAG_PREFIX="dropbox:"應(yīng)用程序可以利用DropBox來做事情,收集日志等1.2.4traces.txt終于到大明星出場的時候了,一起來看一下traces.txt的廬山真面目c以下是筆者寫的一個演示程序制造出的一次ANR勺trace信息:/文件中輸出的第一個進(jìn)程的trace信息,正是發(fā)生ANR勺演示程序/開頭顯示進(jìn)程號、ANRt生的時間點(diǎn)和進(jìn)程名稱-pid9183at2012-09-2822:20:42-Cmdline:com.example.anrdemoDALVIKTHREADS:/以下
30、是各個線程的函數(shù)堆棧信息/mutexes表示虛擬機(jī)實(shí)例中各種線程相關(guān)對象鎖的value值(mutexes:tll=0tsl=0tscl=0ghl=0hwl=0hwll=0)/依次是:線程名、線程優(yōu)先級、線程創(chuàng)建時的序號、線程當(dāng)前狀態(tài)"main"prio=5tid=1TIMED_WAIT/依次是:線程組名稱、suspendCount、debugSuspendCount、線程的Java對象地址、線程的Native對象地址|group="main"sCount=1dsCount=0obj=0x4025b1b8self=0xce68/sysTid是線程號,主線程
31、的線程號和進(jìn)程號相同|sysTid=9183nice=0sched=0/0cgrp=defaulthandle=-1345002368|schedstat=(140838632210998525213)atjava.lang.VMThread.sleep(NativeMethod)atjava.lang.Thread.sleep(Thread.java:1213)atjava.lang.Thread.sleep(Thread.java:1195)atcom.example.anrdemo.ANRActivity.makeANR(ANRActivity.java:44)atcom.example
32、.anrdemo.ANRActivity.onClick(ANRActivity.java:38)atandroid.view.View.performClick(View.java:2486)atandroid.view.View$PerformClick.run(View.java:9130)atandroid.os.Handler.handleCallback(Handler.java:587)atandroid.os.Handler.dispatchMessage(Handler.java:92)atandroid.os.Looper.loop(Looper.java:130)atan
33、droid.app.ActivityThread.main(ActivityThread.java:3703)atjava.lang.reflect.Method.invokeNative(NativeMethod)atjava.lang.reflect.Method.invoke(Method.java:507)ernal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:841)ernal.os.ZygoteInit.main(ZygoteInit.java:599
34、)atdalvik.system.NativeStart.main(NativeMethod)/Binder線程是進(jìn)程的線程池中用來處理binder請求的線程"BinderThread#2"prio=5tid=8NATIVE|group="main"sCount=1dsCount=0obj=0x40750b90self=0x1440b8|sysTid=9190nice=0sched=0/0cgrp=defaulthandle=1476256|schedstat=(915528184631354)atdalvik.system.NativeStart.ru
35、n(NativeMethod)"BinderThread#1"prio=5tid=7NATIVE|group="main"sCount=1dsCount=0obj=0x4074f848self=0x78d40|sysTid=9189nice=0sched=0/0cgrp=defaulthandle=1308088|schedstat=(35095232554321210)atdalvik.system.NativeStart.run(NativeMethod)/線程名稱后面標(biāo)識有daemon,說明這是個守護(hù)線程"Compiler"da
36、emonprio=5tid=6VMWAIT|group="system"sCount=1dsCount=0obj=0x4074b928self=0x141e78|sysTid=9188nice=0sched=0/0cgrp=defaulthandle=1506000|schedstat=(2160643821636964101)atdalvik.system.NativeStart.run(NativeMethod)/JDWP線程是支持虛擬機(jī)調(diào)試的線程,不需要關(guān)心"JDWP"daemonprio=5tid=5VMWAIT|group="syst
37、em"sCount=1dsCount=0obj=0x4074b878self=0x16c958|sysTid=9187nice=0sched=0/0cgrp=defaulthandle=1510224|schedstat=(36621128076177)atdalvik.system.NativeStart.run(NativeMethod)/"SignalCatcher”負(fù)責(zé)接收和處理kernel發(fā)送的各種信號,例如SIGNAL_QUITSIGNAL_USR1就是被該線程/接收到,這個文件的內(nèi)容就是由該線程負(fù)責(zé)輸出的,可以看到它的狀態(tài)是RUNNABLE不過此線程也不需要關(guān)
38、心"SignalCatcher"daemonprio=5tid=4RUNNABLE|group="system"sCount=0dsCount=0obj=0x4074b7b8self=0x150008|sysTid=9186nice=0sched=0/0cgrp=defaulthandle=1501664|schedstat=(170898562866219)atdalvik.system.NativeStart.run(NativeMethod)"GC"daemonprio=5tid=3VMWAIT|group="syst
39、em"sCount=1dsCount=0obj=0x4074b710self=0x168010|sysTid=9185nice=0sched=0/0cgrp=defaulthandle=1503184|schedstat=(30517648217782)atdalvik.system.NativeStart.run(NativeMethod)"HeapWorker"daemonprio=5tid=2VMWAIT|group="system"sCount=1dsCount=0obj=0x4074b658self=0x16a080|sysTid=9
40、184nice=0sched=0/0cgrp=defaulthandle=550856|schedstat=(336914072633666915)atdalvik.system.NativeStart.run(NativeMethod)-end9183-pid127at2012-09-2822:20:42-Cmdline:system_server./省略其他進(jìn)程的信息有一個關(guān)鍵點(diǎn)需要注意:?線程有很多狀態(tài),了解這些狀態(tài)的意義對分析ANR勺原因是有幫助的,總結(jié)如下:Thread.java中定義的狀態(tài)Thread.cpp中定義的狀說明態(tài)TERMINATEDZOMBIE線程死亡,終止運(yùn)行RUNN
41、ABLERUNNING/RUNNABLE線程可運(yùn)行或正在運(yùn)行執(zhí)行了帝有超時參數(shù)的wait、TIMED_WAITINGTIMED_WAITsleep或join函數(shù)BLOCKEDMONITOR線程阻塞,等待獲取對象鎖執(zhí)行了洞時參數(shù)的wait函WAITINGWAIT數(shù)新建,正在初始化,為其分配NEWINITIALIZING資源NEWSTARTING新建,正在啟動RUNNABLENATIVE正在執(zhí)行JNI本地函數(shù)WAITINGVMWAIT正在等待VM資源線程暫停,通常是由丁GC或RUNNABLESUSPENDEDdebug被暫停UNKNOWN未知狀態(tài)Thread.java中的狀態(tài)和Thread.cpp
42、中的狀態(tài)是有對應(yīng)關(guān)系的??梢钥吹角罢吒痈爬?,也比較容易理解,面向Java的使用者;而后者更詳細(xì),面向虛擬機(jī)內(nèi)部的環(huán)境。traces.txt中顯示的線程狀態(tài)都是Thread.cpp中定義的。另外,所有的線程都是遵循POSIX標(biāo)準(zhǔn)的本地線程。關(guān)于線程更多的說明可以查閱源碼/dalvik/vm/Thread.cpp中的說明。<!-線程的ThreadGroup最好也寫進(jìn)去->traces.txt文件中的這些信息是由每個Dalvik進(jìn)程的SignalCatcher線程輸出的,相關(guān)代碼可以查看/dalvik/vm/目錄下的SignalCatcher.cpp:logThreadStacks函數(shù)
43、和Thread.cpp:dvmDumpAllThreadsEx函數(shù)。另外請注意,輸出堆棧信息時SignalCatcher會暫停所有線程。通過該文件很容易就能知道問題進(jìn)程的主線程發(fā)生ANR寸正在執(zhí)行怎樣的操作。例如上述示例,ANRActivity在makeANI®數(shù)中執(zhí)行線程sleep時發(fā)生ANR可以推測sleep時間過長,超過了超時上限導(dǎo)致。這是一種比較簡單的情況,實(shí)際開發(fā)中會遇到很多詭異的、更加復(fù)雜的情況,在后面的實(shí)例講解一節(jié)會詳細(xì)說明。1.2.5CPU使用率這部分的內(nèi)容主要涉及到Linux的相關(guān)知識,數(shù)據(jù)是從“/proc/stat'文件中讀取的,Android中僅僅是匯總
44、和記錄這些數(shù)據(jù)而已,熟悉Linux的讀者可以跳過本節(jié)內(nèi)容。前面簡單說明了CPU®用率信息,我們回顧一下,這次會有更多的知識點(diǎn)要說明。E/ActivityManager(127):ANRincom.example.anrdemo(com.example.anrdemo/.ANRActivity)E/ActivityManager(127):Reason:keyDispatchingTimedOutE/ActivityManager(127):Load:3.85/3.41/3.16/?CPU平均負(fù)載/AN收生之前的一段時間內(nèi)的CPUS用率E/ActivityManager(127):CP
45、Uusagefrom26835msto3662msagowith99%awake:/E/ActivityManager(127):9.4%98/mediaserver:9.4%user+0%kernelE/ActivityManager(127):8.9%127/system_server:6.9%user+2%kernel/faults:1823minor/minor或者major的貞錯誤次數(shù).E/ActivityManager(127):/+0%5033/com.example.anrdemo:0%user+0%kernelE/ActivityManager(127):39%TOTAL:3
46、2%user+6.1%kernel/AN收生之后的一段時間內(nèi)的CPUS用率E/ActivityManager(127):CPUusagefrom601msto1132mslaterwith99%awake:E/ActivityManager(127):10%127/system_server:1.7%user+8.9%kernel/faults:5minorE/ActivityManager(127):10%163/InputDispatcher:1.7%user+8.9%kernelE/ActivityManager(127):1.7%127/system_server:1.7%user+0
47、%kernelE/ActivityManager(127):1.7%135/SurfaceFlinger:0%user+1.7%kernelE/ActivityManager(127):1.7%2814/BinderThread#:1.7%user+0%kernel.E/ActivityManager(127):37%TOTAL:27%user+9.2%kernel以上信息其實(shí)包含了兩個概念:CPU負(fù)載和CPU®用率,它們是不同的。不過負(fù)載的概念主要是做大型服務(wù)器端應(yīng)用時關(guān)注的性能指標(biāo),在Android開發(fā)中我們更加關(guān)注的是使用率。下面詳細(xì)說明,有八個關(guān)鍵點(diǎn)需要注意:CPU負(fù)載/平均
48、負(fù)載CPU載是指某一時刻系統(tǒng)中運(yùn)行隊(duì)列長度之和加上當(dāng)前正在CPU上運(yùn)行的進(jìn)程數(shù),而CPU¥均負(fù)載可以理解為一段時間內(nèi)正在使用和等待使用CPUW活動進(jìn)程的平均數(shù)景。在Linux中“活動進(jìn)程”是指當(dāng)前狀態(tài)為運(yùn)行或不可中斷阻塞的進(jìn)程。通常所說的負(fù)載其實(shí)就是指平均負(fù)載。用一個從網(wǎng)上看到的很生動的例子來說明(不考慮CPU寸間片的限制),把設(shè)備中的一個單核CPUt匕作一個電話亭,把進(jìn)程比作正在使用和等待使用電話的人,假如有一個人正在打電話,有三個人在排隊(duì)等待,此刻電話亭的負(fù)載就是4。使用中會不斷的有人打完電話離開,也會不斷的有其他人排隊(duì)等待,為了得到一個有參考價值的負(fù)載值,可以規(guī)定每隔5秒記錄一
49、下電話亭的負(fù)載,并將某一時刻之前的一分鐘、五分鐘、十五分鐘的的負(fù)載情況分別求平均值,最終就得到了三個時段的平均負(fù)載。實(shí)際上我們通常關(guān)心的就是在某一時刻的前一分鐘、五分鐘、十五分鐘的CP坪均負(fù)載,例如以上日志中這三個值分別是3.85、3.41、3.16,說明前一分鐘內(nèi)正在使用和等待使用CPU勺活動進(jìn)程平均有3.85個,依此類推。在大型服務(wù)器端應(yīng)用中主要關(guān)注的是第五分鐘和第十五分鐘的兩個值,但是Android主要應(yīng)用在便攜手持設(shè)備中,有特殊的軟硬件環(huán)境和應(yīng)用場景,短時間內(nèi)的系統(tǒng)的較高負(fù)載就有可能造成ANR所以筆者認(rèn)為一分鐘內(nèi)的平均負(fù)載相對來說更具有參考價值。CPU勺負(fù)載和使用率沒有必然關(guān)系,有可能
50、只有一個進(jìn)程在使用CPU但執(zhí)行的是復(fù)雜的操作;也有可能等待和正在使用CPU勺進(jìn)程很多,但每個進(jìn)程執(zhí)行的都是簡單操作。實(shí)際處理問題時偶爾會遇到由于平均負(fù)載高引起的ANR典型的特征就是系統(tǒng)中應(yīng)用進(jìn)程數(shù)最多,CPU總使用率較高,但是每個進(jìn)程的CPU®用率不高,當(dāng)前應(yīng)用進(jìn)程主線程沒有異常阻塞,一分鐘內(nèi)的CPUF均負(fù)載較高。提示:Linux內(nèi)核不斷進(jìn)行著CPU負(fù)載的記錄,我們可以在任意時刻通過在shell中執(zhí)行“cat/proc/loadavg”查看。ANR發(fā)生之前和之后一段時間的CPU®用率CPU®用率可以理解為一段時間(記作T)內(nèi)除CPLS閑時間(記作I)之外的時間與這
51、段時間T的比值,用公式表示可以寫為:CPU®用率=(T-I)/T而時間段T是兩個采樣時間點(diǎn)的時間差值。之所以可以這樣計算,是因?yàn)長inux內(nèi)核會把從系統(tǒng)啟動開始到當(dāng)前時刻CP姑動的所有時間信息都記錄下來,我們可以通過查看“/proc/stat文件獲取這些信息。主要包括以下幾種時間,這些時間都是從系統(tǒng)啟動開始計算的,單位都是0.01秒:user:CPU在用戶態(tài)的運(yùn)行時間,不包括nice值為負(fù)數(shù)的進(jìn)程運(yùn)行的時間nice:CPU在用戶態(tài)并且nice值為負(fù)數(shù)的進(jìn)程運(yùn)行的時間system:CPUB內(nèi)核態(tài)運(yùn)行的時間idle:CPU空閑時間,不包括iowait時間iowait:CPU等待I/O操作
52、的時間irq:CPU硬中斷的時間softirq:CPUC中斷的時間注意:隨著Linux內(nèi)核版本的不同,包含的時間類型有可能不同,例如2.6.11中增加的stealstolen等。但根據(jù)Android源碼,我們只需要關(guān)心以上七種類型即可。CPL®用率的計算是在ProcessStats類中實(shí)現(xiàn)的。如果在某兩個時刻T1和T2(T1<T2)進(jìn)行采樣記錄,CPU®用率的整個算法可以歸納為以下幾個公式:userTime=(user2+nice2)-(user1+nice1)systemTime=system2-system1idleTime=idle2-idle1iowaitTi
53、me=iowait2-iowait1irqTime=irq2-irqlsoftirqTime=softirq2-softirqlTotalTime=userTime+systemTime+idleTime+iowaitTime+irqTime+softirqTime有了以上數(shù)據(jù)就可以計算具體的使用率了,例如用戶態(tài)CPU®用率為:userCpuUsage=userTime/TotalTime依此類推可以計算其他類型的使用率。而整個時間段內(nèi)CPU®用率為:CpuUsage=(TotalTime-idleTime)/TotalTime以上計算的是整個系統(tǒng)的CPLK用率,對于指定進(jìn)程的使用率是通過讀取該進(jìn)程的“/proc/進(jìn)程號/stat”文件計算的,而對于指定進(jìn)程的指定線程的使用率是通過讀取該線程的“/proc/進(jìn)程號/task/線程號/stat”文件計算的。進(jìn)程和線程的CPU®用率只包含該進(jìn)程或線程的總使用率、用戶態(tài)使用率和內(nèi)核態(tài)使用率。AM睢執(zhí)行appNotResponding函數(shù)過程中,共輸出了兩個時間段的CPU使用率,通常情
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 2025年度玻璃隔斷行業(yè)安全風(fēng)險評估與控制合同3篇
- 二零二五版美容美發(fā)產(chǎn)品跨境電商銷售合作協(xié)議4篇
- 玻璃幕墻維修施工方案
- 二零二五版美容院供應(yīng)鏈管理及股權(quán)投資協(xié)議4篇
- 環(huán)氧砂漿施工方案
- 2025年P(guān)DA市場拓展專用采購合同3篇
- 2025年度智能家居公司成立合作協(xié)議書正式版4篇
- 2025年度新型農(nóng)業(yè)貸款合同標(biāo)的特征分析3篇
- 2024版鋁單板采購合同
- 會展搭建施工方案
- 地測防治水技能競賽理論考試題庫(含答案)
- 以諾書-中英對照
- 三角形與全等三角形復(fù)習(xí)教案 人教版
- 《朝天子·詠喇叭-王磐》核心素養(yǎng)目標(biāo)教學(xué)設(shè)計、教材分析與教學(xué)反思-2023-2024學(xué)年初中語文統(tǒng)編版
- 成長小說智慧樹知到期末考試答案2024年
- 紅色革命故事《王二小的故事》
- 海洋工程用高性能建筑鋼材的研發(fā)
- 英語48個國際音標(biāo)課件(單詞帶聲、附有聲國際音標(biāo)圖)
- GB/T 6892-2023一般工業(yè)用鋁及鋁合金擠壓型材
- 冷庫安全管理制度
- 2023同等學(xué)力申碩統(tǒng)考英語考試真題
評論
0/150
提交評論