日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 运维知识 > Android >内容正文

Android

Android应用开发性能优化完全分析,完美收官

發(fā)布時(shí)間:2024/8/1 Android 65 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Android应用开发性能优化完全分析,完美收官 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

可以看見,上面這些導(dǎo)致卡頓的原因都是我們平時(shí)開發(fā)中非常常見的。有些人可能會覺得自己的應(yīng)用用著還蠻OK的,其實(shí)那是因?yàn)槟銢]進(jìn)行一些瞬時(shí)測試和壓力測試,一旦在這種環(huán)境下運(yùn)行你的App你就會發(fā)現(xiàn)很多性能問題。

2-3 應(yīng)用UI卡頓分析解決方法


分析UI卡頓我們一般都借助工具,通過工具一般都可以直觀的分析出問題原因,從而反推尋求優(yōu)化方案,具體如下細(xì)說各種強(qiáng)大的工具。

2-3-1 使用HierarchyViewer分析UI性能

我們可以通過SDK提供的工具HierarchyViewer來進(jìn)行UI布局復(fù)雜程度及冗余等分析,如下:

xxx@ThinkPad:~$ hierarchyviewer //通過命令啟動HierarchyViewer

選中一個(gè)Window界面item,然后點(diǎn)擊右上方Hierarchy window或者Pixel Perfect window(這里不介紹,主要用來檢查像素屬性的)即可操作。

先看下Hierarchy window,如下:

一個(gè)Activity的View樹,通過這個(gè)樹可以分析出View嵌套的冗余層級,左下角可以輸入View的id直接自動跳轉(zhuǎn)到中間顯示;Save as PNG用來把左側(cè)樹保存為一張圖片;Capture Layers用來保存psd的PhotoShop分層素材;右側(cè)劇中顯示選中View的當(dāng)前屬性狀態(tài);右下角顯示當(dāng)前View在Activity中的位置等;左下角三個(gè)進(jìn)行切換;Load View Hierarchy用來手動刷新變化(不會自動刷新的)。當(dāng)我們選擇一個(gè)View后會如下圖所示:

類似上圖可以很方便的查看到當(dāng)前View的許多信息;上圖最底那三個(gè)彩色原點(diǎn)代表了當(dāng)前View的性能指標(biāo),從左到右依次代表測量、布局、繪制的渲染時(shí)間,紅色和黃色的點(diǎn)代表速度渲染較慢的View(當(dāng)然了,有些時(shí)候較慢不代表有問題,譬如ViewGroup子節(jié)點(diǎn)越多、結(jié)構(gòu)越復(fù)雜,性能就越差)。

當(dāng)然了,在自定義View的性能調(diào)試時(shí),HierarchyViewer上面的invalidate Layout和requestLayout按鈕的功能更加強(qiáng)大,它可以幫助我們debug自定義View執(zhí)行invalidate()和requestLayout()過程,我們只需要在代碼的相關(guān)地方打上斷點(diǎn)就行了,接下來通過它觀察繪制即可。

可以發(fā)現(xiàn),有了HierarchyViewer調(diào)試工具,我們的UI性能分析變得十分容易,這個(gè)工具也是我們開發(fā)中調(diào)試UI的利器,在平時(shí)寫代碼時(shí)會時(shí)常伴隨我們左右。

2-3-2 使用GPU過度繪制分析UI性能

我們對于UI性能的優(yōu)化還可以通過開發(fā)者選項(xiàng)中的GPU過度繪制工具來進(jìn)行分析。在設(shè)置->開發(fā)者選項(xiàng)->調(diào)試GPU過度繪制(不同設(shè)備可能位置或者叫法不同)中打開調(diào)試后可以看見如下圖(對settings當(dāng)前界面過度繪制進(jìn)行分析):

可以發(fā)現(xiàn),開啟后在我們想要調(diào)試的應(yīng)用界面中可以看到各種顏色的區(qū)域,具體含義如下:

| 顏色 | 含義 |

| — | — |

| 無色 | WebView等的渲染區(qū)域 |

| 藍(lán)色 | 1x過度繪制 |

| 綠色 | 2x過度繪制 |

| 淡紅色 | 3x過度繪制 |

| 紅色 | 4x(+)過度繪制 |

由于過度繪制指在屏幕的一個(gè)像素上繪制多次(譬如一個(gè)設(shè)置了背景色的TextView就會被繪制兩次,一次背景一次文本;這里需要強(qiáng)調(diào)的是Activity設(shè)置的Theme主題的背景不被算在過度繪制層級中),所以最理想的就是繪制一次,也就是藍(lán)色(當(dāng)然這在很多絢麗的界面是不現(xiàn)實(shí)的,所以大家有個(gè)度即可,我們的開發(fā)性能優(yōu)化標(biāo)準(zhǔn)要求最極端界面下紅色區(qū)域不能長期持續(xù)超過屏幕三分之一,可見還是比較寬松的規(guī)定),因此我們需要依據(jù)此顏色分布進(jìn)行代碼優(yōu)化,譬如優(yōu)化布局層級、減少沒必要的背景、暫時(shí)不顯示的View設(shè)置為GONE而不是INVISIBLE、自定義View的onDraw方法設(shè)置canvas.clipRect()指定繪制區(qū)域或通過canvas.quickreject()減少繪制區(qū)域等。

2-3-3 使用GPU呈現(xiàn)模式圖及FPS考核UI性能

Android界面流暢度除過視覺感知以外是可以考核的(測試妹子專用),常見的方法就是通過GPU呈現(xiàn)模式圖或者實(shí)時(shí)FPS顯示進(jìn)行考核,這里我們主要針對GPU呈現(xiàn)模式圖進(jìn)行下說明,因?yàn)镕PS考核測試方法有很多(譬如自己寫代碼實(shí)現(xiàn)、第三方App測試、固件支持等),所以不做統(tǒng)一說明。

通過開發(fā)者選項(xiàng)中GPU呈現(xiàn)模式圖工具來進(jìn)行流暢度考量的流程是(注意:如果是在開啟應(yīng)用后才開啟此功能,記得先把應(yīng)用結(jié)束后重新啟動)在設(shè)置->開發(fā)者選項(xiàng)->GPU呈現(xiàn)模式(不同設(shè)備可能位置或者叫法不同)中打開調(diào)試后可以看見如下圖(對settings當(dāng)前界面上下滑動列表后的圖表):

當(dāng)然,也可以在執(zhí)行完UI滑動操作后在命令行輸入如下命令查看命令行打印的GPU渲染數(shù)據(jù)(分析依據(jù):Draw + Process + Execute = 完整的顯示一幀時(shí)間 < 16ms):

adb shell dumpsys gfxinfo [應(yīng)用包名]

打開上圖可視化工具后,我們可以在手機(jī)畫面上看到豐富的GPU繪制圖形信息,分別展示了StatusBar、NavgationBar、Activity區(qū)域等的GPU渲染時(shí)間信息,隨著界面的刷新,界面上會以實(shí)時(shí)柱狀圖來顯示每幀的渲染時(shí)間,柱狀圖越高表示渲染時(shí)間越長,每個(gè)柱狀圖偏上都有一根代表16ms基準(zhǔn)的綠色橫線,每一條豎著的柱狀線都包含三部分(藍(lán)色代表測量繪制Display List的時(shí)間,紅色代表OpenGL渲染Display List所需要的時(shí)間,黃色代表CPU等待GPU處理的時(shí)間),只要我們每一幀的總時(shí)間低于基準(zhǔn)線就不會發(fā)生UI卡頓問題(個(gè)別超出基準(zhǔn)線其實(shí)也不算啥問題的)。

可以發(fā)現(xiàn),這個(gè)工具是有局限性的,他雖然能夠看出來有幀耗時(shí)超過基準(zhǔn)線導(dǎo)致了丟幀卡頓,但卻分析不到造成丟幀的具體原因。所以說為了配合解決分析UI丟幀卡頓問題我們還需要借助traceview和systrace來進(jìn)行原因追蹤,下面我們會介紹這兩種工具的。

2-3-4 使用Lint進(jìn)行資源及冗余UI布局等優(yōu)化

上面說了,冗余資源及邏輯等也可能會導(dǎo)致加載和執(zhí)行緩慢,所以我們就來看看Lint這個(gè)工具是如何發(fā)現(xiàn)優(yōu)化這些問題的(當(dāng)然了,Lint實(shí)際的功能是非常強(qiáng)大的,我們開發(fā)中也是經(jīng)常使用它來發(fā)現(xiàn)一些問題的,這里主要有點(diǎn)針對UI性能的說明了,其他的雷同)。

在Android Studio 1.4版本中使用Lint最簡單的辦法就是將鼠標(biāo)放在代碼區(qū)點(diǎn)擊右鍵->Analyze->Inspect Code–>界面選擇你要檢測的模塊->點(diǎn)擊確認(rèn)開始檢測,等待一下后會發(fā)現(xiàn)如下結(jié)果:

可以看見,Lint檢測完后給了我們很多建議的,我們重點(diǎn)看一個(gè)關(guān)于UI性能的檢測結(jié)果;上圖中高亮的那一行明確說明了存在冗余的UI層級嵌套,所以我們是可以點(diǎn)擊跳進(jìn)去進(jìn)行優(yōu)化處理掉的。

當(dāng)然了,Lint還有很多功能,大家可以自行探索發(fā)揮,這里只是達(dá)到拋磚引玉的作用。

2-3-5 使用Memory監(jiān)測及GC打印與Allocation Tracker進(jìn)行UI卡頓分析

關(guān)于Android的內(nèi)存管理機(jī)制下面的一節(jié)會詳細(xì)介紹,這里我們主要針對GC導(dǎo)致的UI卡頓問題進(jìn)行詳細(xì)說明。

Android系統(tǒng)會依據(jù)內(nèi)存中不同的內(nèi)存數(shù)據(jù)類型分別執(zhí)行不同的GC操作,常見應(yīng)用開發(fā)中導(dǎo)致GC頻繁執(zhí)行的原因主要可能是因?yàn)槎虝r(shí)間內(nèi)有大量頻繁的對象創(chuàng)建與釋放操作,也就是俗稱的內(nèi)存抖動現(xiàn)象,或者短時(shí)間內(nèi)已經(jīng)存在大量內(nèi)存暫用介于閾值邊緣,接著每當(dāng)有新對象創(chuàng)建時(shí)都會導(dǎo)致超越閾值觸發(fā)GC操作。

如下是我工作中一個(gè)項(xiàng)目的一次經(jīng)歷(我將代碼回退特意抓取的),出現(xiàn)這個(gè)問題的場景是一次壓力測試導(dǎo)致整個(gè)系統(tǒng)卡頓,瞬間殺掉應(yīng)用就OK了,究其原因最終查到是一個(gè)API的調(diào)運(yùn)位置寫錯(cuò)了方式,導(dǎo)致一直被狂調(diào),當(dāng)普通使用時(shí)不會有問題,壓力測試必現(xiàn)卡頓。具體內(nèi)存參考圖如下:

與此抖動圖對應(yīng)的LogCat抓取如下:

//截取其中比較密集一段LogCat,與上圖Memory檢測到的抖動圖對應(yīng),其中xxx為應(yīng)用包名

10-06 00:59:45.619 xxx I/art: Explicit concurrent mark sweep GC freed 72515(3MB) AllocSpace objects, 65(2028KB) LOS objects, 80% free, 17MB/89MB, paused 3.505ms total 60.958ms

10-06 00:59:45.749 xxx I/art: Explicit concurrent mark sweep GC freed 5396(193KB) AllocSpace objects, 0(0B) LOS objects, 75% free, 23MB/95MB, paused 2.079ms total 100.522ms

10-06 00:59:48.059 xxx I/art: Explicit concurrent mark sweep GC freed 4693(172KB) AllocSpace objects, 0(0B) LOS objects, 75% free, 23MB/95MB, paused 2.227ms total 101.692ms

我們知道,類似上面logcat打印一樣,觸發(fā)垃圾回收的主要原因有以下幾種:

  • GC_MALLOC——內(nèi)存分配失敗時(shí)觸發(fā);

  • GC_CONCURRENT——當(dāng)分配的對象大小超過一個(gè)限定值(不同系統(tǒng))時(shí)觸發(fā);

  • GC_EXPLICIT——對垃圾收集的顯式調(diào)用(System.gc()) ;

  • GC_EXTERNAL_ALLOC——外部內(nèi)存分配失敗時(shí)觸發(fā);

可以看見,這種不停的大面積打印GC導(dǎo)致所有線程暫停的操作必定會導(dǎo)致UI視覺的卡頓,所以我們要避免此類問題的出現(xiàn),具體的常見優(yōu)化方式如下:

  • 檢查代碼,盡量避免有些頻繁觸發(fā)的邏輯方法中存在大量對象分配;

  • 盡量避免在多次for循環(huán)中頻繁分配對象;

  • 避免在自定義View的onDraw()方法中執(zhí)行復(fù)雜的操作及創(chuàng)建對象(譬如Paint的實(shí)例化操作不要寫在onDraw()方法中等);

  • 對于并發(fā)下載等類似邏輯的實(shí)現(xiàn)盡量避免多次創(chuàng)建線程對象,而是交給線程池處理。

當(dāng)然了,有了上面說明GC導(dǎo)致的性能后我們就該定位分析問題了,可以通過運(yùn)行DDMS->Allocation Tracker標(biāo)簽打開一個(gè)新窗口,然后點(diǎn)擊Start Tracing按鈕,接著運(yùn)行你想分析的代碼,運(yùn)行完畢后點(diǎn)擊Get Allocations按鈕就能夠看見一個(gè)已分配對象的列表,如下:

點(diǎn)擊上面第一個(gè)表格中的任何一項(xiàng)就能夠在第二個(gè)表格中看見導(dǎo)致該內(nèi)存分配的棧信息,通過這個(gè)工具我們可以很方便的知道代碼分配了哪類對象、在哪個(gè)線程、哪個(gè)類、哪個(gè)文件的哪一行。譬如我們可以通過Allocation Tracker分別做一次Paint對象實(shí)例化在onDraw與構(gòu)造方法的一個(gè)自定義View的內(nèi)存跟蹤,然后你就明白這個(gè)工具的強(qiáng)大了。

PS一句,Android Studio新版本除過DDMS以外在Memory視圖的左側(cè)已經(jīng)集成了Allocation Tracker功能,只是用起來還是沒有DDMS的方便實(shí)用,如下圖:

2-3-6 使用Traceview和dmtracedump進(jìn)行分析優(yōu)化

關(guān)于UI卡頓問題我們還可以通過運(yùn)行Traceview工具進(jìn)行分析,他是一個(gè)分析器,記錄了應(yīng)用程序中每個(gè)函數(shù)的執(zhí)行時(shí)間;我們可以打開DDMS然后選擇一個(gè)進(jìn)程,接著點(diǎn)擊上面的“Start Method Profiling”按鈕(紅色小點(diǎn)變?yōu)楹谏撮_始運(yùn)行),然后操作我們的卡頓UI(小范圍測試,所以操作最好不要超過5s),完事再點(diǎn)一下剛才按的那個(gè)按鈕,稍等片刻即可出現(xiàn)下圖,如下:

花花綠綠的一幅圖我們怎么分析呢?下面我們解釋下如何通過該工具定位問題:

整個(gè)界面包括上下兩部分,上面是你測試的進(jìn)程中每個(gè)線程運(yùn)行的時(shí)間線,下面是每個(gè)方法(包含parent及child)執(zhí)行的各個(gè)指標(biāo)的值。通過上圖的時(shí)間面板可以直觀發(fā)現(xiàn),整個(gè)trace時(shí)間段main線程做的事情特別多,其他的做的相對較少。當(dāng)我們選擇上面的一個(gè)線程后可以發(fā)現(xiàn)下面的性能面板很復(fù)雜,其實(shí)這才是TraceView的核心圖表,它主要展示了線程中各個(gè)方法的調(diào)用信息(CPU使用時(shí)間、調(diào)用次數(shù)等),這些信息就是我們分析UI性能卡頓的核心關(guān)注點(diǎn),所以我們先看幾個(gè)重要的屬性說明,如下:

| 屬性名 | 含義 |

| — | — |

| name | 線程中調(diào)運(yùn)的方法名; |

| Incl CPU Time | 當(dāng)前方法(包含內(nèi)部調(diào)運(yùn)的子方法)執(zhí)行占用的CPU時(shí)間; |

| Excl CPU Time | 當(dāng)前方法(不包含內(nèi)部調(diào)運(yùn)的子方法)執(zhí)行占用的CPU時(shí)間; |

| Incl Real Time | 當(dāng)前方法(包含內(nèi)部調(diào)運(yùn)的子方法)執(zhí)行的真實(shí)時(shí)間,ms單位; |

| Excl Real Time | 當(dāng)前方法(不包含內(nèi)部調(diào)運(yùn)的子方法)執(zhí)行的真實(shí)時(shí)間,ms單位; |

| Calls+Recur Calls/Total | 當(dāng)前方法被調(diào)運(yùn)的次數(shù)及遞歸調(diào)運(yùn)占總調(diào)運(yùn)次數(shù)百分比; |

| CPU Time/Call | 當(dāng)前方法調(diào)運(yùn)CPU時(shí)間與調(diào)運(yùn)次數(shù)比,即當(dāng)前方法平均執(zhí)行CPU耗時(shí)時(shí)間; |

| Real Time/Call | 當(dāng)前方法調(diào)運(yùn)真實(shí)時(shí)間與調(diào)運(yùn)次數(shù)比,即當(dāng)前方法平均執(zhí)行真實(shí)耗時(shí)時(shí)間;(重點(diǎn)關(guān)注) |

有了對上面Traceview圖表的一個(gè)認(rèn)識之后我們就來看看具體導(dǎo)致UI性能后該如何切入分析,一般Traceview可以定位兩類性能問題:

  • 方法調(diào)運(yùn)一次需要耗費(fèi)很長時(shí)間導(dǎo)致卡頓;

  • 方法調(diào)運(yùn)一次耗時(shí)不長,但被頻繁調(diào)運(yùn)導(dǎo)致累計(jì)時(shí)長卡頓。

譬如我們來舉個(gè)實(shí)例,有時(shí)候我們寫完App在使用時(shí)不覺得有啥大的影響,但是當(dāng)我們啟動完App后靜止在那卻十分費(fèi)電或者導(dǎo)致設(shè)備發(fā)熱,這種情況我們就可以打開Traceview然后按照Cpu Time/Call或者Real Time/Call進(jìn)行降序排列,然后打開可疑的方法及其child進(jìn)行分析查看,然后再回到代碼定位檢查邏輯優(yōu)化即可;當(dāng)然了,我們也可以通過該工具來trace我們自定義View的一些方法來權(quán)衡性能問題,這里不再一一列舉嘍。

可以看見,Traceview能夠幫助我們分析程序性能,已經(jīng)很方便了,然而Traceview家族還有一個(gè)更加直觀強(qiáng)大的小工具,那就是可以通過dmtracedump生成方法調(diào)用圖。具體做法如下:

dmtracedump -g result.png target.trace //結(jié)果png文件 目標(biāo)trace文件

通過這個(gè)生成的方法調(diào)運(yùn)圖我們可以更加直觀的發(fā)現(xiàn)一些方法的調(diào)運(yùn)異常現(xiàn)象。不過本人優(yōu)化到現(xiàn)在還沒怎么用到它,每次用到Traceview分析就已經(jīng)搞定問題了,所以說dmtracedump自己酌情使用吧。

PS一句,Android Studio新版本除過DDMS以外在CPU視圖的左側(cè)已經(jīng)集成了Traceview(start Method Tracing)功能,只是用起來還是沒有DDMS的方便實(shí)用(這里有一篇AS MT個(gè)人覺得不錯(cuò)的分析文章(引用自網(wǎng)絡(luò),鏈接屬于原作者功勞)),如下圖:

2-3-7 使用Systrace進(jìn)行分析優(yōu)化

Systrace其實(shí)有些類似Traceview,它是對整個(gè)系統(tǒng)進(jìn)行分析(同一時(shí)間軸包含應(yīng)用及SurfaceFlinger、WindowManagerService等模塊、服務(wù)運(yùn)行信息),不過這個(gè)工具需要你的設(shè)備內(nèi)核支持trace(命令行檢查/sys/kernel/debug/tracing)且設(shè)備是eng或userdebug版本才可以,所以使用前麻煩自己確認(rèn)一下。

我們在分析UI性能時(shí)一般只關(guān)注圖形性能(所以必須選擇Graphics和View,其他隨意),同時(shí)一般對于卡頓的抓取都是5s,最多10s。啟動Systrace進(jìn)行數(shù)據(jù)抓取可以通過兩種方式,命令行方式如下:

python systrace.py --time=10 -o mynewtrace.html sched gfx view wm

圖形模式:

打開DDMS->Capture system wide trace using Android systrace->設(shè)置時(shí)間與選項(xiàng)點(diǎn)擊OK就開始了抓取,接著操作APP,完事生成一個(gè)trace.html文件,用Chrome打開即可如下圖:

在Chrome中瀏覽分析該文件我們可以通過鍵盤的W-A-S-D鍵來搞定,由于上面我們在進(jìn)行trace時(shí)選擇了一些選項(xiàng),所以上圖生成了左上方相關(guān)的CPU頻率、負(fù)載、狀態(tài)等信息,其中的CPU N代表了CPU核數(shù),每個(gè)CPU行的柱狀圖表代表了當(dāng)前時(shí)間段當(dāng)前核上的運(yùn)行信息;下面我們再來看看SurfaceFlinger的解釋,如下:

可以看見上面左邊欄的SurfaceFlinger其實(shí)就是負(fù)責(zé)繪制Android程序UI的服務(wù),所以SurfaceFlinger能反應(yīng)出整體繪制情況,可以關(guān)注上圖VSYNC-app一行可以發(fā)現(xiàn)前5s多基本都能夠達(dá)到16ms刷新間隔,5s多開始到7s多大于了15ms,說明此時(shí)存在繪制丟幀卡頓;同時(shí)可以發(fā)現(xiàn)surfaceflinger一行明顯存在類似不規(guī)律間隔,這是因?yàn)橛械牡胤绞遣恍枰匦落秩綰I,所以有大范圍不規(guī)律,有的是因?yàn)樽枞麑?dǎo)致不規(guī)律,明顯可以發(fā)現(xiàn)0到4s間大多是不需要渲染,而5s以后大多是阻塞導(dǎo)致;對應(yīng)這個(gè)時(shí)間點(diǎn)我們放大可以看到每個(gè)部分所使用的時(shí)間和正在執(zhí)行的任務(wù),具體如下:

可以發(fā)現(xiàn)具體的執(zhí)行明顯存在超時(shí)性能卡頓(原點(diǎn)不是綠色的基本都代表存在一定問題,下面和右側(cè)都會提示你選擇的幀相關(guān)詳細(xì)信息或者alert信息),但是遺憾的是通過Systrace只能大體上發(fā)現(xiàn)是否存在性能問題,具體問題還需要通過Traceview或者代碼中嵌入Trace工具類等去繼續(xù)詳細(xì)分析,總之很蛋疼。

PS:如果你想使用Systrace很輕松的分析定位所有問題,看明白所有的行含義,你還需要具備非常扎實(shí)的Android系統(tǒng)框架的原理才可以將該工具使用的得心應(yīng)手。

2-3-8 使用traces.txt文件進(jìn)行ANR分析優(yōu)化

ANR(Application Not Responding)是Android中AMS與WMS監(jiān)測應(yīng)用響應(yīng)超時(shí)的表現(xiàn);之所以把臭名昭著的ANR單獨(dú)作為UI性能卡頓的分析來說明是因?yàn)锳NR是直接卡死UI不動且必須要解掉的Bug,我們必須盡量在開發(fā)時(shí)避免他的出現(xiàn),當(dāng)然了,萬一出現(xiàn)了那就用下面介紹的方法來分析吧。

我們應(yīng)用開發(fā)中常見的ANR主要有如下幾類:

  • 按鍵觸摸事件派發(fā)超時(shí)ANR,一般閾值為5s(設(shè)置中開啟ANR彈窗,默認(rèn)有事件派發(fā)才會觸發(fā)彈框ANR);

  • 廣播阻塞ANR,一般閾值為10s(設(shè)置中開啟ANR彈窗,默認(rèn)不彈框,只有l(wèi)og提示);

  • 服務(wù)超時(shí)ANR,一般閾值為20s(設(shè)置中開啟ANR彈窗,默認(rèn)不彈框,只有l(wèi)og提示);

當(dāng)ANR發(fā)生時(shí)除過logcat可以看見的log以外我們還可以在系統(tǒng)指定目錄下找到traces文件或dropbox文件進(jìn)行分析,發(fā)生ANR后我們可以通過如下命令得到ANR trace文件:

adb pull /data/anr/traces.txt ./

然后我們用txt編輯器打開可以發(fā)現(xiàn)如下結(jié)構(gòu)分析:

//顯示進(jìn)程id、ANR發(fā)生時(shí)間點(diǎn)、ANR發(fā)生進(jìn)程包名

----- pid 19073 at 2015-10-08 17:24:38 -----

Cmd line: com.example.yanbo.myapplication

//一些GC等object信息,通常可以忽略

//ANR方法堆棧打印信息!重點(diǎn)!

DALVIK THREADS (18):

“main” prio=5 tid=1 Sleeping

| group=“main” sCount=1 dsCount=0 obj=0x7497dfb8 self=0x7f9d09a000

| sysTid=19073 nice=0 cgrp=default sched=0/0 handle=0x7fa106c0a8

| state=S schedstat=( 125271779 68162762 280 ) utm=11 stm=1 core=0 HZ=100

| stack=0x7fe90d3000-0x7fe90d5000 stackSize=8MB

| held mutexes=

at java.lang.Thread.sleep!(Native method)

  • sleeping on <0x0a2ae345> (a java.lang.Object)

at java.lang.Thread.sleep(Thread.java:1031)

  • locked <0x0a2ae345> (a java.lang.Object)

//真正導(dǎo)致ANR的問題點(diǎn),可以發(fā)現(xiàn)是onClick中有sleep導(dǎo)致。我們平時(shí)可以類比分析即可,這里不詳細(xì)說明。

at java.lang.Thread.sleep(Thread.java:985)

at com.example.yanbo.myapplication.MainActivity$1.onClick(MainActivity.java:21)

at android.view.View.performClick(View.java:4908)

at android.view.View$PerformClick.run(View.java:20389)

at android.os.Handler.handleCallback(Handler.java:815)

at android.os.Handler.dispatchMessage(Handler.java:104)

at android.os.Looper.loop(Looper.java:194)

at android.app.ActivityThread.main(ActivityThread.java:5743)

at java.lang.reflect.Method.invoke!(Native method)

at java.lang.reflect.Method.invoke(Method.java:372)

at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:988)

at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:783)

//省略一些不常關(guān)注堆棧打印

至此常見的應(yīng)用開發(fā)中ANR分析定位就可以解決了。

2-4 應(yīng)用UI性能分析解決總結(jié)


可以看見,關(guān)于Android UI卡頓的性能分析還是有很多工具的,上面只是介紹了應(yīng)用開發(fā)中我們經(jīng)常使用的一些而已,還有一些其他的,譬如Oprofile等工具不怎么常用,這里就不再詳細(xì)介紹。

通過上面UI性能的原理、原因、工具分析總結(jié)可以發(fā)現(xiàn),我們在開發(fā)應(yīng)用時(shí)一定要時(shí)刻重視性能問題,如若真的沒留意出現(xiàn)了性能問題,不妨使用上面的一些案例方式進(jìn)行分析。但是那終歸是補(bǔ)救措施,在我們知道上面UI卡頓原理之后我們應(yīng)該盡量從項(xiàng)目代碼架構(gòu)搭建及編寫時(shí)就避免一些UI性能問題,具體項(xiàng)目中常見的注意事項(xiàng)如下:

  • 布局優(yōu)化;盡量使用include、merge、ViewStub標(biāo)簽,盡量不存在冗余嵌套及過于復(fù)雜布局(譬如10層就會直接異常),盡量使用GONE替換INVISIBLE,使用weight后盡量將width和heigh設(shè)置為0dp減少運(yùn)算,Item存在非常復(fù)雜的嵌套時(shí)考慮使用自定義Item View來取代,減少measure與layout次數(shù)等。

  • 列表及Adapter優(yōu)化;盡量復(fù)用getView方法中的相關(guān)View,不重復(fù)獲取實(shí)例導(dǎo)致卡頓,列表盡量在滑動過程中不進(jìn)行UI元素刷新等。

  • 背景和圖片等內(nèi)存分配優(yōu)化;盡量減少不必要的背景設(shè)置,圖片盡量壓縮處理顯示,盡量避免頻繁內(nèi)存抖動等問題出現(xiàn)。

  • 自定義View等繪圖與布局優(yōu)化;盡量避免在draw、measure、layout中做過于耗時(shí)及耗內(nèi)存操作,尤其是draw方法中,盡量減少draw、measure、layout等執(zhí)行次數(shù)。

  • 避免ANR,不要在UI線程中做耗時(shí)操作,遵守ANR規(guī)避守則,譬如多次數(shù)據(jù)庫操作等。

當(dāng)然了,上面只是列出了我們項(xiàng)目中常見的一些UI性能注意事項(xiàng)而已,相信還有很多其他的情況這里沒有說到,歡迎補(bǔ)充。還有一點(diǎn)就是我們上面所謂的UI性能優(yōu)化分析總結(jié)等都是建議性的,因?yàn)樾阅苓@個(gè)問題是一個(gè)涉及面很廣很泛的問題,有些優(yōu)化不是必需的,有些優(yōu)化是必需的,有些優(yōu)化掉以后又是得不償失的,所以我們一般著手解決那些必須的就可以了。

【工匠若水 http://blog.csdn.net/yanbober 轉(zhuǎn)載請注明出處。點(diǎn)我開始Android技術(shù)交流】

3 應(yīng)用開發(fā)Memory內(nèi)存性能分析優(yōu)化

========================

說完了應(yīng)用開發(fā)中的UI性能問題后我們就該來關(guān)注應(yīng)用開發(fā)中的另一個(gè)重要、嚴(yán)重、非常重要的性能問題了,那就是內(nèi)存性能優(yōu)化分析。Android其實(shí)就是嵌入式設(shè)備,嵌入式設(shè)備核心關(guān)注點(diǎn)之一就是內(nèi)存資源;有人說現(xiàn)在的設(shè)備都在堆硬件配置(譬如國產(chǎn)某米的某兔跑分手機(jī)、盒子等),所以內(nèi)存不會再像以前那么緊張了,其實(shí)這句話聽著沒錯(cuò),但為啥再牛逼配置的Android設(shè)備上有些應(yīng)用還是越用系統(tǒng)越卡呢?這里面的原因有很多,不過相信有了這一章下面的內(nèi)容分析,作為一個(gè)移動開發(fā)者的你就有能力打理好自己應(yīng)用的那一畝三分地內(nèi)存了,能做到這樣就足以了。關(guān)于Android內(nèi)存優(yōu)化,這里有一篇Google的官方指導(dǎo)文檔,但是本文為自己項(xiàng)目摸索,會有很多不一樣的地方。

3-1 Android內(nèi)存管理原理


系統(tǒng)級內(nèi)存管理:

Android系統(tǒng)內(nèi)核是基于Linux,所以說Android的內(nèi)存管理其實(shí)也是Linux的升級版而已。Linux在進(jìn)程停止后就結(jié)束該進(jìn)程,而Android把這些停止的進(jìn)程都保留在內(nèi)存中,直到系統(tǒng)需要更多內(nèi)存時(shí)才選擇性的釋放一些,保留在內(nèi)存中的進(jìn)程默認(rèn)(不包含后臺service與Thread等單獨(dú)UI線程的進(jìn)程)不會影響整體系統(tǒng)的性能(速度與電量等)且當(dāng)再次啟動這些保留在內(nèi)存的進(jìn)程時(shí)可以明顯提高啟動速度,不需要再去加載。

再直白點(diǎn)就是說Android系統(tǒng)級內(nèi)存管理機(jī)制其實(shí)類似于Java的垃圾回收機(jī)制,這下明白了吧;在Android系統(tǒng)中框架會定義如下幾類進(jìn)程、在系統(tǒng)內(nèi)存達(dá)到規(guī)定的不同level閾值時(shí)觸發(fā)清空不同level的進(jìn)程類型。

可以看見,所謂的我們的Service在后臺跑著跑著掛了,或者盒子上有些大型游戲啟動起來就掛(之前我在上家公司做盒子時(shí)遇見過),有一個(gè)直接的原因就是這個(gè)閾值定義的太大,導(dǎo)致系統(tǒng)一直認(rèn)為已經(jīng)達(dá)到閾值,所以進(jìn)行優(yōu)先清除了符合類型的進(jìn)程。所以說,該閾值的設(shè)定是有一些講究的,額,扯多了,我們主要是針對應(yīng)用層內(nèi)存分析的,系統(tǒng)級內(nèi)存回收了解這些就基本夠解釋我們應(yīng)用在設(shè)備上的一些表現(xiàn)特征了。

應(yīng)用級內(nèi)存管理:

在說應(yīng)用級別內(nèi)存管理原理時(shí)大家先想一個(gè)問題,假設(shè)有一個(gè)內(nèi)存為1G的Android設(shè)備,上面運(yùn)行了一個(gè)非常非常吃內(nèi)存的應(yīng)用,如果沒有任何機(jī)制的情況下是不是用著用著整個(gè)設(shè)備會因?yàn)槲覀冞@個(gè)應(yīng)用把1G內(nèi)存吃光然后整個(gè)系統(tǒng)運(yùn)行癱瘓呢?

哈哈,其實(shí)Google的工程師才不會這么傻的把系統(tǒng)設(shè)計(jì)這么差勁。為了使系統(tǒng)不存在我們上面假想情況且能安全快速的運(yùn)行,Android的框架使得每個(gè)應(yīng)用程序都運(yùn)行在單獨(dú)的進(jìn)程中(這些應(yīng)用進(jìn)程都是由Zygote進(jìn)程孵化出來的,每個(gè)應(yīng)用進(jìn)程都對應(yīng)自己唯一的虛擬機(jī)實(shí)例);如果應(yīng)用在運(yùn)行時(shí)再存在上面假想的情況,那么癱瘓的只會是自己的進(jìn)程,不會直接影響系統(tǒng)運(yùn)行及其他進(jìn)程運(yùn)行。

既然每個(gè)Android應(yīng)用程序都執(zhí)行在自己的虛擬機(jī)中,那了解Java的一定明白,每個(gè)虛擬機(jī)必定會有堆內(nèi)存閾值限制(值得一提的是這個(gè)閾值一般都由廠商依據(jù)硬件配置及設(shè)備特性自己設(shè)定,沒有統(tǒng)一標(biāo)準(zhǔn),可以為64M,也可以為128M等;它的配置是在Android的屬性系統(tǒng)的/system/build.prop中配置dalvik.vm.heapsize=128m即可,若存在dalvik.vm.heapstartsize則表示初始申請大小),也即一個(gè)應(yīng)用進(jìn)程同時(shí)存在的對象必須小于閾值規(guī)定的內(nèi)存大小才可以正常運(yùn)行。

接著我們運(yùn)行的App在自己的虛擬機(jī)中內(nèi)存管理基本就是遵循Java的內(nèi)存管理機(jī)制了,系統(tǒng)在特定的情況下主動進(jìn)行垃圾回收。但是要注意的一點(diǎn)就是在Android系統(tǒng)中執(zhí)行垃圾回收(GC)操作時(shí)所有線程(包含UI線程)都必須暫停,等垃圾回收操作完成之后其他線程才能繼續(xù)運(yùn)行。這些GC垃圾回收一般都會有明顯的log打印出回收類型,常見的如下:

  • GC_MALLOC——內(nèi)存分配失敗時(shí)觸發(fā);

  • GC_CONCURRENT——當(dāng)分配的對象大小超過一個(gè)限定值(不同系統(tǒng))時(shí)觸發(fā);

  • GC_EXPLICIT——對垃圾收集的顯式調(diào)用(System.gc()) ;

  • GC_EXTERNAL_ALLOC——外部內(nèi)存分配失敗時(shí)觸發(fā);

通過上面這幾點(diǎn)的分析可以發(fā)現(xiàn),應(yīng)用的內(nèi)存管理其實(shí)就是一個(gè)蘿卜一個(gè)坑,坑都一般大,你在開發(fā)應(yīng)用時(shí)要保證的是內(nèi)存使用同一時(shí)刻不能超過坑的大小,否則就裝不下了。

3-2 Android內(nèi)存泄露性能分析


有了關(guān)于Android的一些內(nèi)存認(rèn)識,接著我們來看看關(guān)于Android應(yīng)用開發(fā)中常出現(xiàn)的一種內(nèi)存問題—-內(nèi)存泄露。

3-2-1 Android應(yīng)用內(nèi)存泄露概念

眾所周知,在Java中有些對象的生命周期是有限的,當(dāng)它們完成了特定的邏輯后將會被垃圾回收;但是,如果在對象的生命周期本來該被垃圾回收時(shí)這個(gè)對象還被別的對象所持有引用,那就會導(dǎo)致內(nèi)存泄漏;這樣的后果就是隨著我們的應(yīng)用被長時(shí)間使用,他所占用的內(nèi)存越來越大。如下就是一個(gè)最常見簡單的泄露例子(其它的泄露不再一一列舉了):

public final class MainActivity extends Activity {

private DbManager mDbManager;

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

//DbManager是一個(gè)單例模式類,這樣就持有了MainActivity引用,導(dǎo)致泄露

mDbManager = DbManager.getInstance(this);

}

}

可以看見,上面例子中我們讓一個(gè)單例模式的對象持有了當(dāng)前Activity的強(qiáng)引用,那在當(dāng)前Acvitivy執(zhí)行完onDestroy()后,這個(gè)Activity就無法得到垃圾回收,也就造成了內(nèi)存泄露。

內(nèi)存泄露可以引發(fā)很多的問題,常見的內(nèi)存泄露導(dǎo)致問題如下:

  • 應(yīng)用卡頓,響應(yīng)速度慢(內(nèi)存占用高時(shí)JVM虛擬機(jī)會頻繁觸發(fā)GC);

  • 應(yīng)用被從后臺進(jìn)程干為空進(jìn)程(上面系統(tǒng)內(nèi)存原理有介紹,也就是超過了閾值);

  • 應(yīng)用莫名的崩潰(上面應(yīng)用內(nèi)存原理有介紹,也就是超過了閾值OOM);

造成內(nèi)存泄露泄露的最核心原理就是一個(gè)對象持有了超過自己生命周期以外的對象強(qiáng)引用導(dǎo)致該對象無法被正常垃圾回收;可以發(fā)現(xiàn),應(yīng)用內(nèi)存泄露是個(gè)相當(dāng)棘手重要的問題,我們必須重視。

3-2-2 Android應(yīng)用內(nèi)存泄露察覺手段

知道了內(nèi)存泄露的概念之后肯定就是想辦法來確認(rèn)自己的項(xiàng)目是否存在內(nèi)存泄露了,那該如何察覺自己項(xiàng)目是否存在內(nèi)存泄露呢?如下提供了幾種常用的方式:

| 察覺方式 | 場景 |

| — | — |

| AS的Memory窗口 | 平時(shí)用來直觀了解自己應(yīng)用的全局內(nèi)存情況,大的泄露才能有感知。 |

| DDMS-Heap內(nèi)存監(jiān)測工具 | 同上,大的泄露才能有感知。 |

| dumpsys meminfo命令 | 常用方式,可以很直觀的察覺一些泄露,但不全面且常規(guī)足夠用。 |

| leakcanary神器 | 比較強(qiáng)大,可以感知泄露且定位泄露;實(shí)質(zhì)是MAT原理,只是更加自動化了,當(dāng)現(xiàn)有代碼量已經(jīng)龐大成型,且無法很快察覺掌控全局代碼時(shí)極力推薦;或者是偶現(xiàn)泄露的情況下極力推薦。 |

AS的Memory窗口如下,詳細(xì)的說明這里就不解釋了,很簡單很直觀(使用頻率高):

DDMS-Heap內(nèi)存監(jiān)測工具窗口如下,詳細(xì)的說明這里就不解釋了,很簡單(使用頻率不高):

dumpsys meminfo命令如下(使用頻率非常高,非常高效,我的最愛之一,平時(shí)一般關(guān)注幾個(gè)重要的Object個(gè)數(shù)即可判斷一般的泄露;當(dāng)然了,adb shell dumpsys meminfo不跟參數(shù)直接展示系統(tǒng)所有內(nèi)存狀態(tài)):

leakcanary神器使用這里先不說,下文會專題介紹,你會震撼的一B。有了這些工具的定位我們就能很方便的察覺我們App的內(nèi)存泄露問題,察覺到以后該怎么定位分析呢,繼續(xù)往下看。

3-2-3 Android應(yīng)用內(nèi)存泄露leakcanary工具定位分析

leakcanary是一個(gè)開源項(xiàng)目,一個(gè)內(nèi)存泄露自動檢測工具,是著名的GitHub開源組織Square貢獻(xiàn)的,它的主要優(yōu)勢就在于自動化過早的發(fā)覺內(nèi)存泄露、配置簡單、抓取貼心,缺點(diǎn)在于還存在一些bug,不過正常使用百分之九十情況是OK的,其核心原理與MAT工具類似。

關(guān)于leakcanary工具的配置使用方式這里不再詳細(xì)介紹,因?yàn)檎娴暮芎唵?#xff0c;詳情點(diǎn)我參考官方教程學(xué)習(xí)使用即可。

PS:之前在優(yōu)化性能時(shí)發(fā)現(xiàn)我們有一個(gè)應(yīng)用有兩個(gè)界面退出后Activity沒有被回收(dumpsys meminfo發(fā)現(xiàn)一直在加),所以就懷疑可能存在內(nèi)存泄露。但是問題來了,這兩個(gè)Activity的邏輯十分復(fù)雜,代碼也不是我寫的,相關(guān)聯(lián)的代碼量也十分龐大,更加郁悶的是很難判斷是哪個(gè)版本修改導(dǎo)致的,這時(shí)候只知道有泄露,卻無法定位具體原因,使用MAT分析解決掉了一個(gè)可疑泄露后發(fā)現(xiàn)泄露又變成了概率性的。可以發(fā)現(xiàn),對于這種概率性的泄露用MAT去主動抓取肯定是很耗時(shí)耗力的,所以決定直接引入leakcanary神器來檢測項(xiàng)目,后來很快就徹底解決了項(xiàng)目中所有必現(xiàn)的、偶現(xiàn)的內(nèi)存泄露。

總之一點(diǎn),工具再強(qiáng)大也只是幫我們定位可能的泄露點(diǎn),而最核心的GC ROOT泄露信息推導(dǎo)出泄露問題及如何解決還是需要你把住代碼邏輯及泄露核心概念去推理解決。

3-2-4 Android應(yīng)用內(nèi)存泄露MAT工具定位分析

Eclipse Memory Analysis Tools(點(diǎn)我下載)是一個(gè)專門分析Java堆數(shù)據(jù)內(nèi)存引用的工具,我們可以使用它方便的定位內(nèi)存泄露原因,核心任務(wù)就是找到GC ROOT位置即可,哎呀,關(guān)于這個(gè)工具的使用我是真的不想說了,自己搜索吧,實(shí)在簡單、傳統(tǒng)的不行了。

PS:這是開發(fā)中使用頻率非常高的一個(gè)工具之一,麻煩務(wù)必掌握其核心使用技巧,雖然Android Studio已經(jīng)實(shí)現(xiàn)了部分功能,但是真的很難用,遇到問題目前還是使用Eclipse Memory Analysis Tools吧。

原諒我該小節(jié)的放蕩不羈!!!!(其實(shí)我是困了,嗚嗚!)

3-2-5 Android應(yīng)用開發(fā)規(guī)避內(nèi)存泄露建議

有了上面的原理及案例處理其實(shí)還不夠,因?yàn)樯厦孢@些處理辦法是補(bǔ)救的措施,我們正確的做法應(yīng)該是在開發(fā)過程中就養(yǎng)成良好的習(xí)慣和敏銳的嗅覺才對,所以下面給出一些應(yīng)用開發(fā)中常見的規(guī)避內(nèi)存泄露建議:

  • Context使用不當(dāng)造成內(nèi)存泄露;不要對一個(gè)Activity Context保持長生命周期的引用(譬如上面概念部分給出的示例)。盡量在一切可以使用應(yīng)用ApplicationContext代替Context的地方進(jìn)行替換(原理我前面有一篇關(guān)于Context的文章有解釋)。

  • 非靜態(tài)內(nèi)部類的靜態(tài)實(shí)例容易造成內(nèi)存泄漏;即一個(gè)類中如果你不能夠控制它其中內(nèi)部類的生命周期(譬如Activity中的一些特殊Handler等),則盡量使用靜態(tài)類和弱引用來處理(譬如ViewRoot的實(shí)現(xiàn))。

  • 警惕線程未終止造成的內(nèi)存泄露;譬如在Activity中關(guān)聯(lián)了一個(gè)生命周期超過Activity的Thread,在退出Activity時(shí)切記結(jié)束線程。一個(gè)典型的例子就是HandlerThread的run方法是一個(gè)死循環(huán),它不會自己結(jié)束,線程的生命周期超過了Activity生命周期,我們必須手動在Activity的銷毀方法中中調(diào)運(yùn)thread.getLooper().quit();才不會泄露。

  • 對象的注冊與反注冊沒有成對出現(xiàn)造成的內(nèi)存泄露;譬如注冊廣播接收器、注冊觀察者(典型的譬如數(shù)據(jù)庫的監(jiān)聽)等。

  • 創(chuàng)建與關(guān)閉沒有成對出現(xiàn)造成的泄露;譬如Cursor資源必須手動關(guān)閉,WebView必須手動銷毀,流等對象必須手動關(guān)閉等。

  • 不要在執(zhí)行頻率很高的方法或者循環(huán)中創(chuàng)建對象,可以使用HashTable等創(chuàng)建一組對象容器從容器中取那些對象,而不用每次new與釋放。

  • 避免代碼設(shè)計(jì)模式的錯(cuò)誤造成內(nèi)存泄露。

關(guān)于規(guī)避內(nèi)存泄露上面我只是列出了我在項(xiàng)目中經(jīng)常遇見的一些情況而已,肯定不全面,歡迎拍磚!當(dāng)然了,只有我們做到好的規(guī)避加上強(qiáng)有力的判斷嗅覺泄露才能讓我們的應(yīng)用駕馭好自己的一畝三分地。

3-3 Android內(nèi)存溢出OOM性能分析


上面談?wù)摿薃ndroid應(yīng)用開發(fā)的內(nèi)存泄露,下面談?wù)剝?nèi)存溢出(OOM);其實(shí)可以認(rèn)為內(nèi)存溢出與內(nèi)存泄露是交集關(guān)系,具體如下圖:

下面我們就來看看內(nèi)存溢出(OOM)相關(guān)的東東吧。

3-3-1 Android應(yīng)用內(nèi)存溢出OOM概念

上面我們探討了Android內(nèi)存管理和應(yīng)用開發(fā)中的內(nèi)存泄露問題,可以知道內(nèi)存泄露一般影響就是導(dǎo)致應(yīng)用卡頓,但是極端的影響是使應(yīng)用掛掉。前面也提到過應(yīng)用的內(nèi)存分配是有一個(gè)閾值的,超過閾值就會出問題,這里我們就來看看這個(gè)問題—–內(nèi)存溢出(OOM–OutOfMemoryError)。

內(nèi)存溢出的主要導(dǎo)致原因有如下幾類:

  • 應(yīng)用代碼存在內(nèi)存泄露,長時(shí)間積累無法釋放導(dǎo)致OOM;

  • 應(yīng)用的某些邏輯操作瘋狂的消耗掉大量內(nèi)存(譬如加載一張不經(jīng)過處理的超大超高清圖片等)導(dǎo)致超過閾值OOM;

可以發(fā)現(xiàn),無論哪種類型,導(dǎo)致內(nèi)存溢出(OutOfMemoryError)的核心原因就是應(yīng)用的內(nèi)存超過閾值了。

3-3-2 Android應(yīng)用內(nèi)存溢出OOM性能分析

通過上面的OOM概念和那幅交集圖可以發(fā)現(xiàn),要想分析OOM原因和避免OOM需要分兩種情況考慮,泄露導(dǎo)致的OOM,申請過大導(dǎo)致的OOM。

內(nèi)存泄露導(dǎo)致的OOM分析:

這種OOM一旦發(fā)生后會在logcat中打印相關(guān)OutOfMemoryError的異常棧信息,不過你別高興太早,這種情況下導(dǎo)致的OOM打印異常信息是沒有太大作用,因?yàn)檫@種OOM的導(dǎo)致一般都如下圖情況(圖示為了說明問題數(shù)據(jù)和場景有夸張,請忽略):

從圖片可以看見,這種OOM我們有時(shí)也遇到,第一反應(yīng)是去分析OOM異常打印棧,可是后來發(fā)現(xiàn)打印棧打印的地方?jīng)]有啥問題,沒有可優(yōu)化的余地了,于是就郁悶了。其實(shí)這時(shí)候你留心觀察幾個(gè)現(xiàn)象即可,如下:

  • 留意你執(zhí)行觸發(fā)OOM操作前的界面是否有卡頓或者比較密集的GC打印;

  • 使用命令查看下當(dāng)前應(yīng)用占用內(nèi)存情況;

確認(rèn)了以上這些現(xiàn)象你基本可以斷定該OOM的log真的沒用,真正導(dǎo)致問題的原因是內(nèi)存泄露,所以我們應(yīng)該按照上節(jié)介紹的方式去著手排查內(nèi)存泄露問題,解決掉內(nèi)存泄露后紅色空間都能得到釋放,再去顯示一張0.8M的優(yōu)化圖片就不會再報(bào)OOM異常了。

不珍惜內(nèi)存導(dǎo)致的OOM分析:

上面說了內(nèi)存泄露導(dǎo)致的OOM異常,下面我們再來看一幅圖(數(shù)據(jù)和場景描述有夸張,請忽略),如下:

可見,這種類型的OOM就很好定位原因了,一般都可以從OOM后的log中得出分析定位。

如下例子,我們在Activity中的ImageView放置一張未優(yōu)化的特大的(30多M)高清圖片,運(yùn)行直接崩潰如下:

//拋出OOM異常

10-10 09:01:04.873 11703-11703/? E/art: Throwing OutOfMemoryError “Failed to allocate a 743620620 byte allocation with 4194208 free bytes and 239MB until OOM”

10-10 09:01:04.940 11703-11703/? E/art: Throwing OutOfMemoryError “Failed to allocate a 743620620 byte allocation with 4194208 free bytes and 239MB until OOM”

//堆棧打印

10-10 09:01:04.958 11703-11703/? E/AndroidRuntime: FATAL EXCEPTION: main

10-10 09:01:04.958 11703-11703/? E/AndroidRuntime: Process: com.example.application, PID: 11703

10-10 09:01:04.958 11703-11703/? E/AndroidRuntime: java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.application/com.example.myapplication.MainActivity}: android.view.InflateException: Binary XML file line #21: Error inflating class

10-10 09:01:04.958 11703-11703/? E/AndroidRuntime: at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2610)

10-10 09:01:04.958 11703-11703/? E/AndroidRuntime: at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2684)

10-10 09:01:04.958 11703-11703/? E/AndroidRuntime: at android.app.ActivityThread.access$800(ActivityThread.java:177)

10-10 09:01:04.958 11703-11703/? E/AndroidRuntime: at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1542)

10-10 09:01:04.958 11703-11703/? E/AndroidRuntime: at android.os.Handler.dispatchMessage(Handler.java:111)

10-10 09:01:04.958 11703-11703/? E/AndroidRuntime: at android.os.Looper.loop(Looper.java:194)

10-10 09:01:04.958 11703-11703/? E/AndroidRuntime: at android.app.ActivityThread.main(ActivityThread.java:5743)

10-10 09:01:04.958 11703-11703/? E/AndroidRuntime: at java.lang.reflect.Method.invoke(Native Method)

10-10 09:01:04.958 11703-11703/? E/AndroidRuntime: at java.lang.reflect.Method.invoke(Method.java:372)

10-10 09:01:04.958 11703-11703/? E/AndroidRuntime: at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:988)

10-10 09:01:04.958 11703-11703/? E/A

《Android學(xué)習(xí)筆記總結(jié)+最新移動架構(gòu)視頻+大廠安卓面試真題+項(xiàng)目實(shí)戰(zhàn)源碼講義》

【docs.qq.com/doc/DSkNLaERkbnFoS0ZF】 完整內(nèi)容開源分享

ndroidRuntime: at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:783)

//出錯(cuò)地點(diǎn),原因是21行的ImageView設(shè)置的src是一張未優(yōu)化的31M的高清圖片

10-10 09:01:04.958 11703-11703/? E/AndroidRuntime: Caused by: android.view.InflateException: Binary XML file line #21: Error inflating class

10-10 09:01:04.958 11703-11703/? E/AndroidRuntime: at android.view.LayoutInflater.createView(LayoutInflater.java:633)

通過上面的log可以很方便的看出來問題原因所在地,那接下來的做法就是優(yōu)化唄,降低圖片的相關(guān)規(guī)格即可(譬如使用BitmapFactory的Option類操作等)。

PS:提醒一句的是記得應(yīng)用所屬的內(nèi)存是區(qū)分Java堆和native堆的!

3-3-3 Android應(yīng)用規(guī)避內(nèi)存溢出OOM建議

還是那句話,等待OOM發(fā)生是為時(shí)已晚的事,我們應(yīng)該將其扼殺于萌芽之中,至于如何在開發(fā)中規(guī)避OOM,如下給出一些我們應(yīng)用開發(fā)中的常用的策略建議:

  • 時(shí)刻記得不要加載過大的Bitmap對象;譬如對于類似圖片加載我們要通過BitmapFactory.Options設(shè)置圖片的一些采樣比率和復(fù)用等,具體做法點(diǎn)我參考官方文檔,不過過我們一般都用fresco或Glide開源庫進(jìn)行加載。

  • 優(yōu)化界面交互過程中頻繁的內(nèi)存使用;譬如在列表等操作中只加載可見區(qū)域的Bitmap、滑動時(shí)不加載、停止滑動后再開始加載。

  • 有些地方避免使用強(qiáng)引用,替換為弱引用等操作。

  • 避免各種內(nèi)存泄露的存在導(dǎo)致OOM。

  • 對批量加載等操作進(jìn)行緩存設(shè)計(jì),譬如列表圖片顯示,Adapter的convertView緩存等。

  • 盡可能的復(fù)用資源;譬如系統(tǒng)本身有很多字符串、顏色、圖片、動畫、樣式以及簡單布局等資源可供我們直接使用,我們自己也要盡量復(fù)用style等資源達(dá)到節(jié)約內(nèi)存。

  • 對于有緩存等存在的應(yīng)用盡量實(shí)現(xiàn)onLowMemory()和onTrimMemory()方法。

  • 盡量使用線程池替代多線程操作,這樣可以節(jié)約內(nèi)存及CPU占用率。

  • 盡量管理好自己的Service、Thread等后臺的生命周期,不要浪費(fèi)內(nèi)存占用。

  • 盡可能的不要使用依賴注入,中看不中用。

  • 盡量在做一些大內(nèi)存分配等可疑內(nèi)存操作時(shí)進(jìn)行try catch操作,避免不必要的應(yīng)用閃退。

  • 盡量的優(yōu)化自己的代碼,減少冗余,進(jìn)行編譯打包等優(yōu)化對齊處理,避免類加載時(shí)浪費(fèi)內(nèi)存。

可以發(fā)現(xiàn),上面只是列出了我們開發(fā)中常見的導(dǎo)致OOM異常的一些規(guī)避原則,還有很多相信還沒有列出來,大家可以自行追加參考即可。

3-4 Android內(nèi)存性能優(yōu)化總結(jié)


無論是什么電子設(shè)備的開發(fā),內(nèi)存問題永遠(yuǎn)都是一個(gè)很深?yuàn)W、無底洞的話題,上面的這些內(nèi)存分析建議也單單只是Android應(yīng)用開發(fā)中一些常見的場景而已,真正的達(dá)到合理的優(yōu)化還是需要很多知識和功底的。

合理的應(yīng)用架構(gòu)設(shè)計(jì)、設(shè)計(jì)風(fēng)格選擇、開源Lib選擇、代碼邏輯規(guī)范等都會決定到應(yīng)用的內(nèi)存性能,我們必須時(shí)刻頭腦清醒的意識到這些問題潛在的風(fēng)險(xiǎn)與優(yōu)劣,因?yàn)閮?nèi)存優(yōu)化必須要有一個(gè)度,不能一味的優(yōu)化,亦不能置之不理。

【工匠若水 http://blog.csdn.net/yanbober 轉(zhuǎn)載請注明出處。點(diǎn)我開始Android技術(shù)交流】

4 Android應(yīng)用API使用及代碼邏輯性能分析

=============================

在我們開發(fā)中除過常規(guī)的那些經(jīng)典UI、內(nèi)存性能問題外其實(shí)還存在很多潛在的性能優(yōu)化、這種優(yōu)化不是十分明顯,但是在某些場景下卻是非常有必要的,所以我們簡單列舉一些常見的其他潛在性能優(yōu)化技巧,具體如下探討。

4-1 Android應(yīng)用String/StringBuilder/StringBuffer優(yōu)化建議


字符串操作在Android應(yīng)用開發(fā)中是十分常見的操作,也就是這個(gè)最簡單的字符串操作卻也暗藏很多潛在的性能問題,下面我們實(shí)例來說說。

先看下面這個(gè)關(guān)于String和StringBuffer的對比例子:

//性能差的實(shí)現(xiàn)

String str1 = “Name:”;

String str2 = “GJRS”;

總結(jié)

以上是生活随笔為你收集整理的Android应用开发性能优化完全分析,完美收官的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。

九色在线 | 日韩免费在线一区 | 欧美9999| 日韩午夜大片 | 91精品国产一区二区三区 | 欧美日bb| 国产成人福利在线 | 99久免费精品视频在线观看 | 国产一线二线三线性视频 | 亚洲午夜精品久久久久久久久久久久 | 国产一区二区高清视频 | 精品国产一区二区三区久久影院 | 久久经典国产视频 | av在线色| 97视频免费在线看 | 国产亚洲精品免费 | 国产一区欧美日韩 | 97人人爽人人 | 国产精品久久久久免费观看 | 免费成视频 | wwwww.国产 | 亚洲免费视频在线观看 | 亚洲专区在线 | 国产成年人av | 美女在线免费视频 | 毛片网在线播放 | 亚洲天堂自拍视频 | 天天操天天玩 | 亚洲精品在线一区二区三区 | 日韩欧美一区二区在线 | 国产成人精品久久亚洲高清不卡 | 久久久精品国产免费观看同学 | 色婷久久 | 97视频免费在线看 | 美女在线免费观看视频 | 亚洲天堂网视频在线观看 | 久久久久久久99精品免费观看 | 亚洲理论在线观看电影 | 丁香六月综合网 | 婷婷色九月 | 99欧美精品 | 狠狠色丁香婷婷综合久小说久 | 久久影院亚洲 | 免费黄色a级毛片 | 国产成人av电影在线 | 日韩激情在线视频 | 最新日韩在线 | 免费色视频在线 | 午夜久久福利视频 | 在线观看中文字幕一区二区 | 午夜影院三级 | 999电影免费在线观看 | www五月天com| 国产午夜精品一区二区三区四区 | 中文字幕在线国产精品 | 国产男女爽爽爽免费视频 | 成人h电影 | 久久久99精品免费观看乱色 | 日韩av一区在线观看 | 伊人首页 | 久久久久久亚洲精品 | 亚洲精品成人免费 | 欧美激情精品久久久 | 九九九热精品免费视频观看 | 色av资源网 | 成人午夜精品久久久久久久3d | 日韩av在线资源 | 在线免费色 | 91精品在线免费观看视频 | 免费视频黄 | 精品高清美女精品国产区 | 国产香蕉久久 | 亚洲综合一区二区精品导航 | 欧美成人999| 亚洲午夜大片 | 二区三区av| 777xxx欧美| 精品美女视频 | 中文字幕av免费在线观看 | 中文字幕在线资源 | 色中色资源站 | 超碰999 | 中国一 片免费观看 | 亚洲日本va中文字幕 | 国产精品一区二区在线免费观看 | 激情五月在线视频 | av中文字幕免费在线观看 | 狠狠色噜噜狠狠狠狠 | 久久久久国产精品午夜一区 | 国产午夜三级一二三区 | 免费在线观看亚洲视频 | www.色的| 亚洲男人天堂a | 久久色视频 | 中文字幕第 | 一区二区三区日韩在线观看 | 黄色三级在线观看 | 麻豆视频国产精品 | 中文在线免费视频 | 免费91在线| 婷婷精品在线视频 | 91成年人视频 | 97麻豆视频 | 白丝av免费观看 | 色全色在线资源网 | 中文字幕欲求不满 | 精品国产伦一区二区三区 | 国产私拍在线 | 丁香六月婷 | 在线观看爱爱视频 | 毛片精品免费在线观看 | 视频在线观看91 | 国产成人av电影在线观看 | 国产视频日韩视频欧美视频 | 91在线区 | 99精品视频免费全部在线 | 97在线公开视频 | 亚洲人成人在线 | 手机在线中文字幕 | 国产在线观看av | av中文字幕亚洲 | 色婷婷中文 | 国产h片在线观看 | 日日弄天天弄美女bbbb | 久久99久国产精品黄毛片入口 | 天天干.com| 中文字幕在线免费观看 | 国产精品久久久久aaaa九色 | 日韩一区正在播放 | 国产精品免费观看在线 | 国产91在线观看 | 国产91在线看 | 激情伊人五月天久久综合 | 久久a国产 | 夜夜夜夜爽 | 久久首页 | 粉嫩av一区二区三区免费 | 黄色三级在线 | 樱空桃av | 丁香五香天综合情 | 五月激情丁香婷婷 | 免费a视频 | 日韩精品视频一二三 | 日韩最新在线 | 国产在线永久 | 久久精品高清视频 | 亚洲亚洲精品在线观看 | 久久精精品视频 | 新版资源中文在线观看 | 8x成人免费视频 | av在线8| 久久精品国产久精国产 | 久久精品1区 | 亚洲精品国产麻豆 | 天天操天天操天天操天天操天天操 | 国产激情电影综合在线看 | 久久人网| 中文字幕av在线免费 | 五月婷婷天堂 | 国产一区二区在线精品 | 久久久久高清毛片一级 | 精精国产xxxx视频在线播放 | 久久免费av电影 | 成人黄色片在线播放 | 伊人狠狠色丁香婷婷综合 | 欧美精品久久久久久久免费 | 在线看岛国av | 欧美精品在线视频 | 天天玩天天干 | 久久久99精品免费观看 | 欧美成人tv | 狠狠插狠狠操 | 高清免费在线视频 | 一区二区三区四区久久 | 日韩在线国产 | 综合五月 | 岛国大片免费视频 | 福利在线看片 | 精品国产大片 | 久久久久久久亚洲精品 | 日韩中文字幕一区 | 国产精品久久一区二区三区, | 亚在线播放中文视频 | 国产黄a三级三级 | 国产第一页精品 | 日韩精品一卡 | 婷五月天激情 | 欧美日韩高清一区 | 韩国av一区二区 | 在线小视频你懂的 | 日韩啪啪小视频 | 亚洲在线网址 | 欧美日韩不卡一区二区三区 | 91成人精品一区在线播放69 | 五月婷婷中文 | 深爱综合网 | 最新av在线播放 | 超碰免费在线公开 | aaa日本高清在线播放免费观看 | 日日干天天射 | 免费成人短视频 | 久久综合久久八八 | 99国产精品一区 | 久久精品国产久精国产 | 狠狠色丁香婷婷综合久小说久 | 欧美特一级 | 久久免费视频7 | 99久久夜色精品国产亚洲96 | av片在线观看 | 天天色天 | 久艹视频免费观看 | 亚洲欧洲av在线 | 亚洲成人黄色在线 | av福利在线播放 | 色人久久 | 日韩精品一区二区三区免费观看 | www.福利视频 | 人人插人人舔 | 四虎成人精品永久免费av | 亚洲精品日韩一区二区电影 | 中文字幕在线观看完整版电影 | 丁香激情五月 | 丁香激情综合久久伊人久久 | 色婷在线 | 96亚洲精品久久久蜜桃 | 欧美五月婷婷 | 亚洲国产一区在线观看 | 黄色av电影 | 麻豆国产视频 | 精品一区二区在线看 | 成年人免费在线播放 | 国内精品久久久久影院优 | 福利一区在线视频 | 国产精品12345 | 91探花在线 | 免费三及片 | 99国产在线视频 | 区一区二区三区中文字幕 | 国产xxxxx在线观看 | 国产一级片免费播放 | 国产精品区二区三区日本 | 热久久国产精品 | 亚洲一区免费在线 | 97精品国产手机 | 500部大龄熟乱视频 欧美日本三级 | av免费在线看网站 | 日本在线中文 | 亚洲第一av在线播放 | 日韩电影中文字幕 | www.com.黄| 亚洲最大在线视频 | 狠狠操91| 国产福利一区二区三区在线观看 | 国产最新精品视频 | 免费看在线看www777 | 亚洲jizzjizz日本少妇 | 亚洲视频电影在线 | 久久综合免费视频影院 | 中文字幕一区二区三区在线视频 | 国产四虎在线 | 狠狠色狠狠色合久久伊人 | 欧美日韩高清一区二区三区 | 亚洲精品国产精品国 | 久久精品久久精品久久 | 精品国产aⅴ麻豆 | 天天摸天天干天天操天天射 | 精品一区免费 | av资源在线看 | av午夜电影 | 欧美一级免费黄色片 | 精品国产免费人成在线观看 | 一本到在线 | 国产精品福利一区 | 欧美一二三区播放 | 久久久久久久久久网 | 91麻豆精品国产午夜天堂 | 黄色影院在线免费观看 | 婷婷夜夜 | 青草视频免费观看 | 亚洲国产伊人 | 免费在线观看av网址 | av黄色成人 | 玖玖国产精品视频 | 五月开心激情 | www.婷婷com | 日韩精品视频免费专区在线播放 | 欧美日本高清视频 | 国产91免费在线 | 在线观看电影av | 国产做aⅴ在线视频播放 | aaawww| 国产最新在线观看 | 最新av免费在线 | www夜夜操com | 亚洲资源| 丁香花五月 | 999久久久免费视频 午夜国产在线观看 | 国产成人精品久久久久蜜臀 | 国内久久精品 | 久久久精品一区二区 | 亚洲国产高清在线观看视频 | 精品一区二区6 | 久久夜色精品国产亚洲aⅴ 91chinesexxx | 91久久久久久国产精品 | 色香蕉在线视频 | 精品国产伦一区二区三区观看方式 | 成年人视频在线 | 精品视频资源站 | a级国产乱理论片在线观看 伊人宗合网 | 国产xx在线| 国产精品乱码一区二三区 | 久久久久久久国产精品 | 国产在线p | 在线亚洲人成电影网站色www | 很黄很黄的网站免费的 | 国产成人久久精品 | 日韩在线网址 | 欧美日韩亚洲精品在线 | 特级免费毛片 | 制服丝袜在线91 | 超碰在线天天 | 亚洲综合狠狠干 | 久久久片 | 在线黄色观看 | 久久久精品网 | 国产一区欧美日韩 | 就要干b | 东方av在 | 操操色 | 国产精品一区二区在线播放 | 日韩精品无 | 欧美色图亚洲图片 | 日日夜夜婷婷 | 黄色一级大片在线观看 | 四虎影视8848dvd | 久久69精品久久久久久久电影好 | 91麻豆精品91久久久久同性 | 中文字幕在线观看av | 久久精彩 | 国产亚洲免费观看 | 天天碰天天操视频 | 成人av片在线观看 | www成人精品 | 久色伊人 | 国产偷v国产偷∨精品视频 在线草 | 99色在线观看视频 | 色综合天天天天做夜夜夜夜做 | 日日操日日操 | 91热爆在线观看 | 欧美日韩综合在线观看 | 91色偷偷| 不卡的av在线 | 欧美五月婷婷 | 国产精品高潮久久av | 国产99中文字幕 | 亚洲成av人影院 | 99精品久久精品一区二区 | japanesexxxxfreehd乱熟 | 丁香六月激情 | 日韩美女久久 | 成人wwwxxx视频 | 在线观看av中文字幕 | 欧美日韩视频在线观看免费 | 黄色av一区 | 国产精品99久久免费黑人 | 国产精品毛片一区视频 | 国产婷婷久久 | 久久久久久久久久国产精品 | 91香蕉视频在线 | 久久99国产一区二区三区 | 免费av网站在线 | 黄色一级大片免费看 | 在线黄色观看 | 在线观看视频你懂得 | 人人爽人人澡 | 婷婷开心久久网 | 91麻豆精品一区二区三区 | 久久久久久免费毛片精品 | 国产精品嫩草影院99网站 | 999免费视频| 久久免费公开视频 | 在线观看完整版免费 | 99一级片| 操天天操 | 免费看av片网站 | 午夜精品久久久99热福利 | 久久精品一区 | 午夜视频99 | a v在线观看 | 九七视频在线观看 | 悠悠av资源片 | 九九久久电影 | 免费99精品国产自在在线 | 久久久精品综合 | 日韩电影中文字幕 | 狠狠躁夜夜躁人人爽超碰97香蕉 | 免费特级黄色片 | 字幕网在线观看 | 黄色电影在线免费观看 | 国产精品日韩久久久久 | 国产精品久久久久久久7电影 | 国产日本在线观看 | 久久人人做 | www.国产视频 | 国产免费作爱视频 | 日韩精品中字 | 日韩欧美高清免费 | 欧美一区二区在线刺激视频 | 成人中文字幕+乱码+中文字幕 | av中文字幕电影 | 国产日本亚洲高清 | 欧美 日韩 久久 | 91日韩精品视频 | 国产精品入口麻豆www | 国产精品免费一区二区三区在线观看 | 久久久久二区 | 亚洲一级特黄 | 精品婷婷 | 精品国产激情 | 99在线国产| 丁香六月婷婷综合 | 麻豆 91 在线 | 久久福利国产 | 日韩中文字幕视频在线观看 | 国产麻豆剧传媒免费观看 | 中文字幕有码在线播放 | 91麻豆精品国产91久久久久久久久 | 久草a在线| 精品uu | 欧美久久久久久久久 | 久久久精品国产一区二区电影四季 | 骄小bbw搡bbbb揉bbbb | 成人资源在线 | 玖玖在线视频观看 | 特黄一级毛片 | 国产精品免费观看网站 | 色成人亚洲网 | 成全在线视频免费观看 | 日韩电影中文字幕 | 成人羞羞视频在线观看免费 | 色福利网 | 91精品国产92久久久久 | 69绿帽绿奴3pvideos | 成年人毛片在线观看 | 91av看片| 午夜久久久精品 | 在线电影a | 日韩在线观看 | 96视频在线 | 人人澡人摸人人添学生av | 人人澡人人爱 | 亚洲成av人影片在线观看 | 亚洲精品国偷拍自产在线观看 | 成人亚洲精品久久久久 | 国产一区电影在线观看 | www.亚洲黄色 | 97**国产露脸精品国产 | 久久电影国产免费久久电影 | 国产婷婷精品 | 麻豆视频观看 | 国产成人99久久亚洲综合精品 | 丁香婷婷在线观看 | 欧美少妇xxx | 中文字幕在线观看资源 | 成人在线观看资源 | 91人人澡人人爽人人精品 | 天海冀一区二区三区 | 国产精品一二三 | 在线视频欧美精品 | 91精品国产乱码在线观看 | 久久精品123 | 亚洲电影网站 | 午夜精品久久久久久久爽 | 久草在线在线精品观看 | 亚洲精品啊啊啊 | 夜夜澡人模人人添人人看 | 草久中文字幕 | 日日夜夜噜噜噜 | 天天干天天草天天爽 | 欧美一级日韩免费不卡 | 人人干人人添 | 91麻豆精品 | av超碰在线 | 夜夜高潮夜夜爽国产伦精品 | 国产精品福利无圣光在线一区 | 日韩精品久久一区二区 | 中文字幕888 | 狠狠五月婷婷 | 成年人免费看 | 九九视频精品免费 | 国产婷婷精品av在线 | 一区二区精品视频 | 日韩天堂网 | 亚在线播放中文视频 | 国产高清黄色 | 精品久久福利 | 亚州人成在线播放 | 免费在线观看日韩视频 | 一区二区av | 久久精品久久99精品久久 | 在线一区电影 | 日韩av综合网站 | 婷婷中文字幕综合 | 欧美久久综合 | 亚洲婷婷伊人 | 欧美少妇xx | 久草在线视频新 | 日韩高清av| 在线免费观看国产视频 | 91女人18片女毛片60分钟 | 在线综合 亚洲 欧美在线视频 | 久久人人97超碰精品888 | 黄色一级免费电影 | 日韩欧美在线高清 | 午夜精品一区二区三区免费视频 | 国产999精品久久久 免费a网站 | 久久 精品一区 | 日韩三级视频在线观看 | 欧美一级乱黄 | 特级a老妇做爰全过程 | 麻豆传媒精品 | 久久综合电影 | 99视频一区 | 国产精品原创av片国产免费 | 99久久久成人国产精品 | 在线免费中文字幕 | 九九免费精品视频 | 2023天天干 | 日日操狠狠干 | 探花视频网站 | 日韩精品专区在线影院重磅 | 97精品超碰一区二区三区 | 国产精品一区二区三区在线 | 日韩免费观看一区二区三区 | 久久这里只有精品9 | 久久久999免费视频 日韩网站在线 | 最近日本韩国中文字幕 | 亚洲视屏在线播放 | 国产精品不卡视频 | 四虎永久精品在线 | 91精品资源 | 蜜桃av人人夜夜澡人人爽 | 超碰人人99 | 久久精品视频观看 | 日韩专区视频 | 免费观看国产成人 | 国产在线播放观看 | 日韩免费精品 | 五月天婷亚洲天综合网精品偷 | 成人在线黄色电影 | 久久国产一区二区 | 国产九九精品视频 | 中文字幕视频免费观看 | 亚洲一区二区三区精品在线观看 | 国产欧美精品xxxx另类 | 国产麻豆剧传媒免费观看 | 国产精品久久久久久一二三四五 | 久久国语露脸国产精品电影 | 欧美日韩免费一区 | 成年人免费在线观看网站 | 午夜色站| 久久艹中文字幕 | 成人全视频免费观看在线看 | 狠狠狠操 | 成年人网站免费观看 | 黄色av免费看 | 精品亚洲免费 | 色片网站在线观看 | www国产亚洲精品 | 国产一级视频在线免费观看 | 日韩精品aaa | 亚洲97在线 | 国产中文视 | 亚洲少妇天堂 | 中文字幕在线免费观看 | 天天做夜夜做 | 日韩中文字幕免费在线播放 | 9999亚洲| 免费看一级黄色大全 | 久久av免费 | 国产精品私拍 | 亚洲在线观看av | 色综合天天做天天爱 | 中文字幕在线观看你懂的 | 蜜臀久久99精品久久久酒店新书 | 日韩免费专区 | 久久国产手机看片 | 丁香五香天综合情 | 在线免费观看视频你懂的 | 久久午夜国产精品 | 涩涩资源网| av免费线看 | 视频福利在线观看 | 成人久久久精品国产乱码一区二区 | 天天se天天cao天天干 | 欧美在线观看小视频 | 中文字幕高清在线播放 | 国产精品久久久视频 | 欧美成人免费在线 | 丁香六月婷婷 | www视频免费在线观看 | 色婷婷一| 在线观看免费黄色 | 人人射人人插 | 久久亚洲精品国产亚洲老地址 | 成人黄色大片网站 | 亚洲乱码精品久久久 | 日韩h在线观看 | 亚州精品视频 | 国产精品一区二区久久久 | 久久成人在线视频 | 天天做综合网 | 国产精品99在线观看 | 国产婷婷久久 | 夜色成人网 | 精品国产视频在线观看 | 天天综合久久综合 | 日韩字幕 | 国产成人一区二区啪在线观看 | 亚洲日韩欧美一区二区在线 | 四虎欧美| 亚洲国产偷 | 欧美激情精品 | 久久久久久欧美二区电影网 | 国内精品久久久久久久久久 | 手机看片午夜 | 天天操天天干天天插 | 色婷婷99| 伊人射| 99免费国产 | 天天av综合网 | 国产手机视频精品 | 中文字幕 在线看 | 天天操操操操操 | 国产视频2 | 西西人体4444www高清视频 | 99久久精品国产系列 | 精品久久久久一区二区国产 | 狠狠躁夜夜躁人人爽超碰97香蕉 | 亚洲成色777777在线观看影院 | 777久久久 | 中文字幕人成人 | 少妇搡bbbb搡bbb搡aa | 国产成人精品一区二区三区在线观看 | 亚洲第一久久久 | 在线视频 你懂得 | 久久久久久久久久久久国产精品 | 最近日本韩国中文字幕 | 日韩高清在线不卡 | 国产二区免费视频 | 免费成人在线网站 | 国内揄拍国内精品 | 黄色a大片 | 亚洲涩涩网站 | 国产在线精品国自产拍影院 | 天天操天天干天天综合网 | 国产精品门事件 | 久久精品999 | 人人插人人玩 | 久久久久久久综合色一本 | 91av播放 | 欧美日韩在线视频观看 | 99视频在线精品国自产拍免费观看 | 亚洲日韩欧美一区二区在线 | 日韩 精品 一区 国产 麻豆 | 中文字幕一区二区三区四区视频 | 欧美特一级片 | 深夜激情影院 | 日韩三级久久 | 久久久综合 | 国产精品久久一区二区三区不卡 | 91视频中文字幕 | 午夜精品一区二区三区免费视频 | 国产午夜精品一区 | 亚洲更新最快 | 婷婷色综合色 | 中文字幕欧美激情 | 婷婷六月丁香激情 | 三级在线视频观看 | 亚洲人在线视频 | 97精品欧美91久久久久久 | 天天射天天爽 | 粉嫩av一区二区三区免费 | 久久久久久毛片精品免费不卡 | 西西44人体做爰大胆视频 | 午夜精品一二区 | 国内精品久久久久国产 | 久草在线资源观看 | 久草国产在线观看 | 国产精品成人自产拍在线观看 | 超碰97国产精品人人cao | 久久福利在线 | 欧美日一级片 | 日韩www在线 | 国产美女精品在线 | 黄网站免费看 | 久久99精品视频 | 久久久久97国产 | 毛片基地黄久久久久久天堂 | 日本不卡一区二区三区在线观看 | 国产一区黄色 | 国内精品久久久久久久97牛牛 | 97精产国品一二三产区在线 | 成人亚洲综合 | 免费看av片网站 | 日日夜夜爱| 国产在线国偷精品产拍免费yy | 97久久精品午夜一区二区 | 亚欧日韩成人h片 | 国产黑丝一区二区三区 | 天堂v中文 | 国产亚洲精品美女 | 日韩欧美xxxx | 激情影院在线观看 | 久久成人国产精品 | 国产精品美 | 国产精品久久久久久久久久三级 | 日日夜夜狠狠 | 免费a v视频 | 最近中文字幕大全中文字幕免费 | 久福利| 国产麻豆精品传媒av国产下载 | 伊人久久国产精品 | 一区二区三区免费在线观看视频 | 国产成人av福利 | 蜜臀av免费一区二区三区 | 国产色在线,com | 久久综合亚洲鲁鲁五月久久 | 在线涩涩| 亚洲视频免费在线观看 | 久久国产精品99久久久久久老狼 | 操操操日日日 | 成人av电影免费在线播放 | 91日韩精品视频 | 丝袜美腿在线播放 | 在线观看色网 | 日韩精品久久久久久久电影竹菊 | 国产精品21区 | 国产精品久久99综合免费观看尤物 | 亚洲一级免费观看 | 天天激情综合 | 成人影视免费 | 日韩理论| 精品国产一区二区三区久久久 | 国产精品欧美一区二区三区不卡 | 最近高清中文字幕在线国语5 | 国产精品免费一区二区三区 | 国产精品青草综合久久久久99 | 国产日韩欧美在线一区 | 午夜性盈盈 | 99精品久久久久久久 | 美女亚洲精品 | 亚洲精品色视频 | 国内揄拍国产精品 | 婷婷网站天天婷婷网站 | 啪啪免费视频网站 | 国产精品免费av | 9999在线视频 | 免费观看成人 | 99久热在线精品视频观看 | 2019中文在线观看 | 免费在线看v | 亚洲视频在线免费看 | 国产日产在线观看 | 人人讲| 人人插人人插 | 亚洲女在线 | 91在线精品播放 | 国产精品久久久久久久久久久久久 | 日韩欧美视频在线观看免费 | 国产91免费在线 | 香蕉视频在线观看免费 | 日韩精品一区不卡 | 国内精品免费久久影院 | 亚洲天天在线 | 最新中文字幕在线观看视频 | 国产精品黄色av | 超碰人人在线观看 | 91中文字幕永久在线 | 亚洲少妇久久 | 在线观看www. | 日日爽天天爽 | av大片免费在线观看 | 免费看wwwwwwwwwww的视频 久久久久久99精品 91中文字幕视频 | 91精品国产亚洲 | 亚洲国产69| 日韩中文字幕亚洲一区二区va在线 | 九九视频免费在线观看 | 久久精品日本啪啪涩涩 | av成人免费 | 国产精品久久久久久影院 | 中文字幕免费高 | 四虎国产永久在线精品 | 视频国产一区二区三区 | 日韩一区二区久久 | 国产精品原创 | 狠狠色狠狠色合久久伊人 | 国产视频一区在线播放 | 美女福利视频在线 | av黄色免费网站 | 亚洲高清精品在线 | 中文字幕亚洲综合久久五月天色无吗'' | 欧美性生活小视频 | 国产v欧美 | 久久精品99国产国产 | 国产一区免费视频 | 五月婷婷网站 | 免费黄色小网站 | 免费av看片 | 精品国产精品国产偷麻豆 | 天天操综 | 在线国产欧美 | 日本最新高清不卡中文字幕 | 久久理论片| 99国产精品一区 | 97电影网站 | 麻豆国产精品va在线观看不卡 | 超碰在线观看99 | 日日干视频 | 美腿丝袜av | 一区二区不卡视频在线观看 | 久久精品日产第一区二区三区乱码 | 欧美精品少妇xxxxx喷水 | 香蕉视频久久久 | 激情综合网五月 | 91av视频 | 久久久www| 国产在线观看91 | 黄污网站在线观看 | 人人干干人人 | 久久久久久久久久影院 | 成人亚洲欧美 | 97免费视频在线 | 国产日韩在线看 | 久久黄色免费视频 | 国产一级二级三级在线观看 | 永久免费的av电影 | 久久精品久久精品久久精品 | 人人爽人人爽人人爽人人爽 | 免费观看一级视频 | 美女天天操 | 一级黄色片网站 | 97视频在线免费 | www.五月天婷婷 | 国产在线a | 亚洲精品理论 | 成人黄色电影在线观看 | 国产精品igao视频网入口 | 高清视频一区二区三区 | 日韩免费电影网 | 91高清视频在线 | 91精品国产高清自在线观看 | 成人在线视频在线观看 | 麻豆国产在线播放 | 丁香综合 | 综合网婷婷 | 免费日韩 精品中文字幕视频在线 | av免费看网站 | 91系列在线 | 国产丝袜网站 | av大片免费在线观看 | 色久天| 99久久爱 | 91人人干| 97操碰 | 黄www在线观看 | 久久精品久久精品 | 日韩av图片| 亚洲成aⅴ人在线观看 | 精品国产人成亚洲区 | 免费视频xnxx com | 高清一区二区三区 | 91精彩视频在线观看 | 日韩黄色在线电影 | 国产精品精品国产婷婷这里av | 香蕉久草 | 在线播放日韩av | 又大又硬又黄又爽视频在线观看 | 99精品国产一区二区 | 夜夜操天天干, | 亚洲资源在线网 | 日韩r级在线 | www.五月激情.com | 亚洲欧美少妇 | 欧美日韩精品免费观看视频 | 不卡的av电影在线观看 | 国产一区欧美二区 | 毛片a级片 | 96久久欧美麻豆网站 | 狠狠亚洲| 97精品一区 | 国产精品久久久久一区二区三区共 | 国产成人一区二区三区电影 | 国产91成人在在线播放 | 国产成人精品日本亚洲999 | 中文字幕成人网 | 又黄又爽免费视频 | 久久精品人人做人人综合老师 | 国产视频一区精品 | 亚洲三级精品 | 中文字幕在线观看免费观看 | 麻豆视频在线观看免费 | 成人av中文字幕在线观看 | 最新日韩中文字幕 | 在线观看香蕉视频 | 99久久精品国产欧美主题曲 | 久操视频在线免费看 | 青春草免费视频 | 色婷婷六月天 | 狠狠操操 | 91传媒在线观看 | 五月婷婷丁香色 | 国产成人无码AⅤ片在线观 日韩av不卡在线 | 免费日韩一区 | 91黄站| 欧美在线91 | av中文字幕第一页 | 国产精品久久电影网 | a级片网站 | 亚洲精品在线观看不卡 | 亚洲在线成人精品 | 日本在线观看视频一区 | 日韩精品一区二区电影 | 亚洲综合国产精品 | 久视频在线 | 亚洲视频在线看 | 国产精品久久99综合免费观看尤物 | 亚洲三级在线 | av福利在线 | 日本久久免费视频 | 超碰在线人人艹 | 欧美一区二区三区在线观看 | 国产欧美综合在线观看 | 国产区高清在线 | 狠狠干网 | 在线视频婷婷 | 视频 国产区 | 探花视频免费观看 | 免费黄色小网站 | 日韩电影中文字幕在线 | 天天射色综合 | 美女视频国产 | 中文字幕免费高清 | 人人干在线| 日韩欧美v | 国产视频一区在线免费观看 | 天天干天天想 | 成人日韩av| 亚洲片在线资源 | 最新国产精品拍自在线播放 | 日韩激情在线视频 | 国产又黄又猛又粗 | 久热电影| 亚洲免费观看在线视频 | 免费在线观看成人av | 久久久免费av | 免费在线观看av网址 | av 一区二区三区四区 | 国产小视频福利在线 | 欧美激情亚洲综合 | 在线视频99 | 午夜 久久 tv | 亚洲欧洲精品视频 | 亚洲 欧美 变态 国产 另类 | 我爱av激情网 | 久久国产电影院 | 香蕉视频国产在线 | 久久国产网 | 亚洲精品日韩在线观看 | 在线99视频| 在线日韩av| 亚洲成av人影片在线观看 | 国产在线不卡精品 | 久久视精品 | av888.com| 午夜婷婷综合 | 视色网站| jizz欧美性9| 激情综合网五月 | 手机在线欧美 | 国产在线观看高清视频 | 国内久久久久久 | 97精品超碰一区二区三区 | 久产久精国产品 | 国产精品久久久久久久毛片 | 国产成人在线观看 | 日本在线中文 | 成人资源在线观看 | 日本中文字幕一二区观 | 婷久久 | 91在线精品秘密一区二区 | av黄色在线观看 | 久久大片网站 | 国产精品女主播一区二区三区 | 91福利视频一区 | 日韩黄色中文字幕 | 国产伦精品一区二区三区照片91 | 精品免费视频 |