Android系統(tǒng)穩(wěn)定性_第1頁
Android系統(tǒng)穩(wěn)定性_第2頁
Android系統(tǒng)穩(wěn)定性_第3頁
已閱讀5頁,還剩11頁未讀, 繼續(xù)免費閱讀

下載本文檔

版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領

文檔簡介

1、Android系統(tǒng)穩(wěn)定性-ANR1.2如何分析ANR問題引起ANR問題的根本原因,總的來說可以歸納為兩類:應用進程自身引起的,例如:主線程阻塞、掛起、死循環(huán)應用進程的其他線程的CPU占用率高,使得主線程無法搶占到CPU寸間片其他進程間接引起的,例如:當前應用進程進行進程間通信請求其他進程,其他進程的操作長時間沒有反饋其他進程的CPU占用率高,使得當前應用進程無法搶占到CPU寸間片分析ANR問題時,以上述可能的幾種原因為線索,通過分析各種日志信息,大多數(shù)情況下你就可以很容易找到問題所在了。注意:確實有一些ANR問題很難調查清楚,因為整個系統(tǒng)不穩(wěn)定的因素很多,例如LinuxKernel本身的bug

2、引起的內存碎片過多、硬件損壞等。這類比較底層的原因引起的ANR、可題往往無從查起,并且這根本不是應用程序的問題,浪費了應用開發(fā)人員很多時間,如果你從事過整個系統(tǒng)的開發(fā)和維護工作的話會深有體會。所以我不能保證了解了本章的所有內容后能夠解決一切ANR、可題,如果出現(xiàn)了很疑難的ANR、可題,我建議最好去和做驅動和內核的朋友聊聊,或者,如果問題只是個十萬分之一的偶然現(xiàn)象,不影響程序的正常運行,我倒是建議不去理它。1.2.1分析ANR勺利器Android會在ANR生時輸出很多有用的信息幫助分析問題原因,我們先來看一下ANR勺異常信息,使用logcat命令查看會得到類似如下的log:/WindowMana

3、ger所在的進程是system_server,進程號是127I/WindowManager(127):Inputeventdispatchingtimedoutsendingtocom.example.anrdemo/com.example.anrdemo.ANRActivity/system_server進程中的ActivityManagerService請求kernel向5033進程發(fā)送SIGNAL_QUIT肯求你可以在shell中使用命令達到相同的目的:adbshellkill-35033/和其他的Java虛擬機一樣,SIGNAL_QUI如是Dalvik內部支持的功能之I/Process

4、(127):Sendingsignal.PID:5033SIG:3/5033進程的虛擬機實例接收到SIGNAL_QUIT信號后會將進程中各個線程的函數(shù)堆棧信息輸出到traces.txt文件中/發(fā)生ANR的進程正常情況下會第一個輸出I/dalvikvm(5033):threadid=4:reactingtosignal3I/dalvikvm(5033):Wrotestacktracesto'/data/anr/traces.txt'/另外還有其他一些進程/隨后會輸出CPUS用情況E/ActivityManager(127):ANRincom.example.anrdemo(com

5、.example.anrdemo/.ANRActivity)/Reason表示導致ANR'可題的直接原因E/ActivityManager(127):Reason:keyDispatchingTimedOutE/ActivityManager(127):Load:3.85/3.41/3.16/請注意ago,表示ANR生之前的一段時間內的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®用率。以上做了簡單注釋,不過稍后再詳細分析它們。1.2.2ANR信息是如何輸出的我們再來看看這些log是怎樣被輸出的,這很重要,知其然,也要知其所以然。代碼在ActivityManagerService類中,找到它的appNotResponding函數(shù)。finalvoidappNotResponding(ProcessRecord

9、app,ActivityRecordactivity,ActivityRecordparent,finalStringannotation)/firstPids和lastPids兩個集合存放那些將會在traces中輸出信息的進程的進程號ArrayList<Integer>firstPids=newArrayList<Integer>(5);SparseArray<Boolean>lastPids=newSparseArray<Boolean>(20);/mController是IActivityController接口的實例,是為Monkey測試

10、程序預留的,默認為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;/使用一個標志變量避免同一個應用在沒有處理完時重復輸出logapp.notResponding=true;./當前發(fā)生ANR的應用進程被第一個添加進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認為trueupdateCpuStatsNow();/再次更新CPU言息synchronized(mProcessStatsThread)(輸出ANR生前一段時間內的CPUS用率cpuInfo=mProcessStatsprintCurrentState(anrTime);info-appendl

13、processStatsgrintCurrentLoad。);infoappend(cpuInfo);輸出ANR生后一段時間內的CPUS用率infoappend(processStatsprintCurrentState(anrTime);/將ANR信息同時輸出到DropBox中addErrorToDropBox("anr",app,cessName,activity,parent,annotation,cpuInfo,tracesFile,null);./在Android4.0中可以設置是否不顯示AN破示對話框,如果設置的話就不會顯示對話框,并且會殺掉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);有三個關鍵點需要注意: 當前發(fā)生ANR勺應用進程被第一個添加進firstPids集合中,所以會第一個向traces文件中寫入信息。反過來說,traces文件中出現(xiàn)的第一個進程正常情況下就是發(fā)生ANR勺那個進程。不過有

16、時候會很不湊巧,發(fā)生ANR勺進程還沒有來得及輸出trace信息,就由于某種原因退出了,所以偶爾會遇到traces文件中找不到發(fā)生ANR勺進程信息的情況。 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ù),設置文件屆性時經常會用到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;有兩個關鍵點需要注意: 聰明的你肯定已經知道,之所以trace信息會輸出到“/data/anr/tr

20、aces.txt”文件中,就是系統(tǒng)屬性“dalvik.vm.stack-trace-file”設置的。你可以通過在設備的shell中使用setprop和getprop對系統(tǒng)屬性進行設置和讀?。?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)聽應用進程是否已經完成寫入traces文件的操作/Android在判斷桌面壁紙文件是否設置完成時也是用的FileObserver,很有用的類FileObserverobserver=newFileObserver(tracesPath,FileOb

22、server.CLOSE_WRITE)publicsynchronizedvoidonEvent(intevent,Stringpath)notify();./首先輸出firstPids集合中指定的進程,這些也是對ANR問題來說最重要的進程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進程中各個線程的函數(shù)堆棧信息,就可以使用向目標進程發(fā)送SIGNAL_QUIT(3)這個技巧。其實這個名稱有點誤導,它并不會讓進程真正退出。1.2.3DropBox剛才留了一個問題:Android只保留最后一次發(fā)生ANF®寸的traces信息,那么以前的traces信息就丟失了么?為了增強Android的異常信息收集管理能力,從2.2開始增加了DropBox功能。DropBox(簡稱D0是系統(tǒng)進程中的一個服務,在system_server進程啟動時創(chuàng)建,并且它沒有運行在單獨的線程中,而是運行在system_server的Server

24、Thread線程中。我們可以將ServerThread稱作system_server的主線程,ServerThread線程除了啟動并維護各個服務外,還負責檢測一些重要的服務是否死鎖,這一點到后面的Watchdog部分再分析<!-Watchdog寫完后注意補充章節(jié)號->。DB被創(chuàng)建的代碼如下。SystemServer.javaServerThread.run()Slog.i(TAG"DropBoxService");ServiceManager.addService(Context.DROPBOX_SERVICE服務名稱為“dropbox”newDropBoxMa

25、nagerService(context,newFile("/data/system/dropbox");“/data/system/dropbox”是DB指定的文件存放位置。下面來看一下DB服務的主要功能。1.DropBoxManagerServiceDropBoxManagerService(簡稱DBMS就是DB服務的本尊,它的主要功能接口包括以下幾個函數(shù):publicvoidadd(DropBoxManager.Entryentry)DBM翳所有要添加的日志都用DropBoxManager.Entry類型的對象表示,通過add函數(shù)添加,并且直到目前為止一個Entry對

26、象對應著一個日志文件。publicbooleanisTagEnabled(Stringtag)通過給每一個Entry設置一個tag可以標識不同類型的日志,并且可以靈活的啟用/禁用某種類型的日志,isTagEnabled用來判斷指定類型的日志是否被啟用/禁用了,一旦禁用就不會再記錄這種類型的日志。默認是不禁用任何類型的日志的。稍后說明如何啟用/禁用日志。publicsynchronizedDropBoxManager.EntrygetNextEntry(Stringtag,longmillis)我們可以通過getNextEntry函數(shù)獲取指定類型和指定時間點之后的第一條日志,要使用這個功能應用程

27、序需要有“android.permission.READ_LOGS”的權限,并且在使用完畢返回的Entry對象后要調用其close函數(shù)確保關閉日志文件的文件描述符(如果不關閉的話可能造成進程打開的文件描述符超過1024而崩潰,Android中限制每個進程的文件描述符上限為1024)。DBM洗供了很多的配置項用來限制對磁盤的使用,通過SettingsProvider應用程序維護,數(shù)據(jù)存放在其settings.db數(shù)據(jù)庫中。這些配置項也都有默認值,羅列如下:Settings.Secure.DROPBOX_AGE_SECONDS="dropbox_age_seconds"日志文件

28、保存的最長時間,默認3天Settings.Secure.DROPBOX_MAX_FILES="dropbox_max_files"日志文件的最大數(shù)最,默認值是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:"應用程序可以利用DropBox來做事情,收集日志等1.2.4traces.txt終于到大明星出場的時候了,一起來看一下traces.txt的廬山真面目c以下是筆者寫的一個演示程序制造出的一次ANR勺trace信息:/文件中輸出的第一個進程的trace信息,正是發(fā)生ANR勺演示程序/開頭顯示進程號、ANRt生的時間點和進程名稱-pid9183at2012-09-2822:20:42-Cmdline:com.example.anrdemoDALVIKTHREADS:/以下

30、是各個線程的函數(shù)堆棧信息/mutexes表示虛擬機實例中各種線程相關對象鎖的value值(mutexes:tll=0tsl=0tscl=0ghl=0hwl=0hwll=0)/依次是:線程名、線程優(yōu)先級、線程創(chuàng)建時的序號、線程當前狀態(tài)"main"prio=5tid=1TIMED_WAIT/依次是:線程組名稱、suspendCount、debugSuspendCount、線程的Java對象地址、線程的Native對象地址|group="main"sCount=1dsCount=0obj=0x4025b1b8self=0xce68/sysTid是線程號,主線程

31、的線程號和進程號相同|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線程是進程的線程池中用來處理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)/線程名稱后面標識有daemon,說明這是個守護線程"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線程是支持虛擬機調試的線程,不需要關心"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”負責接收和處理kernel發(fā)送的各種信號,例如SIGNAL_QUITSIGNAL_USR1就是被該線程/接收到,這個文件的內容就是由該線程負責輸出的,可以看到它的狀態(tài)是RUNNABLE不過此線程也不需要關

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./省略其他進程的信息有一個關鍵點需要注意:?線程有很多狀態(tài),了解這些狀態(tài)的意義對分析ANR勺原因是有幫助的,總結如下:Thread.java中定義的狀態(tài)Thread.cpp中定義的狀說明態(tài)TERMINATEDZOMBIE線程死亡,終止運行RUNN

41、ABLERUNNING/RUNNABLE線程可運行或正在運行執(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)是有對應關系的??梢钥吹角罢吒痈爬ǎ脖容^容易理解,面向Java的使用者;而后者更詳細,面向虛擬機內部的環(huán)境。traces.txt中顯示的線程狀態(tài)都是Thread.cpp中定義的。另外,所有的線程都是遵循POSIX標準的本地線程。關于線程更多的說明可以查閱源碼/dalvik/vm/Thread.cpp中的說明。<!-線程的ThreadGroup最好也寫進去->traces.txt文件中的這些信息是由每個Dalvik進程的SignalCatcher線程輸出的,相關代碼可以查看/dalvik/vm/目錄下的SignalCatcher.cpp:logThreadStacks函數(shù)

43、和Thread.cpp:dvmDumpAllThreadsEx函數(shù)。另外請注意,輸出堆棧信息時SignalCatcher會暫停所有線程。通過該文件很容易就能知道問題進程的主線程發(fā)生ANR寸正在執(zhí)行怎樣的操作。例如上述示例,ANRActivity在makeANI®數(shù)中執(zhí)行線程sleep時發(fā)生ANR可以推測sleep時間過長,超過了超時上限導致。這是一種比較簡單的情況,實際開發(fā)中會遇到很多詭異的、更加復雜的情況,在后面的實例講解一節(jié)會詳細說明。1.2.5CPU使用率這部分的內容主要涉及到Linux的相關知識,數(shù)據(jù)是從“/proc/stat'文件中讀取的,Android中僅僅是匯總

44、和記錄這些數(shù)據(jù)而已,熟悉Linux的讀者可以跳過本節(jié)內容。前面簡單說明了CPU®用率信息,我們回顧一下,這次會有更多的知識點要說明。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平均負載/AN收生之前的一段時間內的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收生之后的一段時間內的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以上信息其實包含了兩個概念:CPU負載和CPU®用率,它們是不同的。不過負載的概念主要是做大型服務器端應用時關注的性能指標,在Android開發(fā)中我們更加關注的是使用率。下面詳細說明,有八個關鍵點需要注意:CPU負載/平均

48、負載CPU載是指某一時刻系統(tǒng)中運行隊列長度之和加上當前正在CPU上運行的進程數(shù),而CPU¥均負載可以理解為一段時間內正在使用和等待使用CPUW活動進程的平均數(shù)景。在Linux中“活動進程”是指當前狀態(tài)為運行或不可中斷阻塞的進程。通常所說的負載其實就是指平均負載。用一個從網上看到的很生動的例子來說明(不考慮CPU寸間片的限制),把設備中的一個單核CPUt匕作一個電話亭,把進程比作正在使用和等待使用電話的人,假如有一個人正在打電話,有三個人在排隊等待,此刻電話亭的負載就是4。使用中會不斷的有人打完電話離開,也會不斷的有其他人排隊等待,為了得到一個有參考價值的負載值,可以規(guī)定每隔5秒記錄一

49、下電話亭的負載,并將某一時刻之前的一分鐘、五分鐘、十五分鐘的的負載情況分別求平均值,最終就得到了三個時段的平均負載。實際上我們通常關心的就是在某一時刻的前一分鐘、五分鐘、十五分鐘的CP坪均負載,例如以上日志中這三個值分別是3.85、3.41、3.16,說明前一分鐘內正在使用和等待使用CPU勺活動進程平均有3.85個,依此類推。在大型服務器端應用中主要關注的是第五分鐘和第十五分鐘的兩個值,但是Android主要應用在便攜手持設備中,有特殊的軟硬件環(huán)境和應用場景,短時間內的系統(tǒng)的較高負載就有可能造成ANR所以筆者認為一分鐘內的平均負載相對來說更具有參考價值。CPU勺負載和使用率沒有必然關系,有可能

50、只有一個進程在使用CPU但執(zhí)行的是復雜的操作;也有可能等待和正在使用CPU勺進程很多,但每個進程執(zhí)行的都是簡單操作。實際處理問題時偶爾會遇到由于平均負載高引起的ANR典型的特征就是系統(tǒng)中應用進程數(shù)最多,CPU總使用率較高,但是每個進程的CPU®用率不高,當前應用進程主線程沒有異常阻塞,一分鐘內的CPUF均負載較高。提示:Linux內核不斷進行著CPU負載的記錄,我們可以在任意時刻通過在shell中執(zhí)行“cat/proc/loadavg”查看。ANR發(fā)生之前和之后一段時間的CPU®用率CPU®用率可以理解為一段時間(記作T)內除CPLS閑時間(記作I)之外的時間與這

51、段時間T的比值,用公式表示可以寫為:CPU®用率=(T-I)/T而時間段T是兩個采樣時間點的時間差值。之所以可以這樣計算,是因為Linux內核會把從系統(tǒng)啟動開始到當前時刻CP姑動的所有時間信息都記錄下來,我們可以通過查看“/proc/stat文件獲取這些信息。主要包括以下幾種時間,這些時間都是從系統(tǒng)啟動開始計算的,單位都是0.01秒:user:CPU在用戶態(tài)的運行時間,不包括nice值為負數(shù)的進程運行的時間nice:CPU在用戶態(tài)并且nice值為負數(shù)的進程運行的時間system:CPUB內核態(tài)運行的時間idle:CPU空閑時間,不包括iowait時間iowait:CPU等待I/O操作

52、的時間irq:CPU硬中斷的時間softirq:CPUC中斷的時間注意:隨著Linux內核版本的不同,包含的時間類型有可能不同,例如2.6.11中增加的stealstolen等。但根據(jù)Android源碼,我們只需要關心以上七種類型即可。CPL®用率的計算是在ProcessStats類中實現(xiàn)的。如果在某兩個時刻T1和T2(T1<T2)進行采樣記錄,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依此類推可以計算其他類型的使用率。而整個時間段內CPU®用率為:CpuUsage=(TotalTime-idleTime)/TotalTime以上計算的是整個系統(tǒng)的CPLK用率,對于指定進程的使用率是通過讀取該進程的“/proc/進程號/stat”文件計算的,而對于指定進程的指定線程的使用率是通過讀取該線程的“/proc/進程號/task/線程號/stat”文件計算的。進程和線程的CPU®用率只包含該進程或線程的總使用率、用戶態(tài)使用率和內核態(tài)使用率。AM睢執(zhí)行appNotResponding函數(shù)過程中,共輸出了兩個時間段的CPU使用率,通常情

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網頁內容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
  • 4. 未經權益所有人同意不得將文件中的內容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網僅提供信息存儲空間,僅對用戶上傳內容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內容本身不做任何修改或編輯,并不能對任何下載內容負責。
  • 6. 下載文件中如有侵權或不適當內容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論