android性能優(yōu)化

工具

LeakCanary 数初,https://www.liaohuqiu.net/cn/posts/leak-canary-read-me/
debugImplementation 'com.squareup.leakcanary:leakcanary-android:1.5'
releaseImplementation 'com.squareup.leakcanary:leakcanary-android-no-op:1.5' 穩(wěn)定版,兼容6.0

BlockCanary:https://github.com/markzhai/AndroidPerformanceMonitor
compile 'com.github.markzhai:blockcanary-android:1.5.0'

重點:systrace + 函數(shù)插樁

Memory Analysis Tool(MAT)绍坝,

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

內(nèi)存檢查:

https://www.cnblogs.com/yezhennan/p/5442557.html
內(nèi)存耗用名詞解析:
VSS - Virtual Set Size 虛擬耗用內(nèi)存(包含共享庫占用的內(nèi)存)
RSS - Resident Set Size 實際使用物理內(nèi)存(包含共享庫占用的內(nèi)存)
PSS - Proportional Set Size 實際使用的物理內(nèi)存(比例分配共享庫占用的內(nèi)存)
USS - Unique Set Size 進(jìn)程獨自占用的物理內(nèi)存(不包含共享庫占用的內(nèi)存)
一般來說內(nèi)存占用大小有如下規(guī)律:VSS >= RSS >= PSS >= USS

OOM:

內(nèi)存泄露可以引發(fā)很多的問題:
1.程序卡頓宵荒,響應(yīng)速度慢(內(nèi)存占用高時JVM虛擬機(jī)會頻繁觸發(fā)GC)
2.莫名消失(當(dāng)你的程序所占內(nèi)存越大汁雷,它在后臺的時候就越可能被干掉。反之內(nèi)存占用越小报咳,在后臺存在的時間就越長)
3.直接崩潰(OutOfMemoryError)

ANDROID內(nèi)存面臨的問題:

1.有限的堆內(nèi)存侠讯,原始只有16M
2.內(nèi)存大小消耗等根據(jù)設(shè)備,操作系統(tǒng)等級暑刃,屏幕尺寸的不同而不同
3.程序不能直接控制
4.支持后臺多任務(wù)處理(multitasking)
5.運行在虛擬機(jī)之上

5R:

本文主要通過如下的5R方法來對ANDROID內(nèi)存進(jìn)行優(yōu)化:
1.Reckon(計算)
首先需要知道你的app所消耗內(nèi)存的情況厢漩,知己知彼才能百戰(zhàn)不殆

2.Reduce(減少)
消耗更少的資源

3.Reuse(重用)
當(dāng)?shù)谝淮问褂猛暌院螅M量給其他的使用

4.Review(檢查)
回顧檢查你的程序岩臣,看看設(shè)計或代碼有什么不合理的地方溜嗜。

5.Recycle(回收)
返回資源給生產(chǎn)流

下面從系統(tǒng)內(nèi)存(system ram)和堆內(nèi)存(heap)兩個方面介紹一些查看和計算內(nèi)存使用情況的方法:

1.系統(tǒng)內(nèi)存:
procstats,meminfo他們一個側(cè)重于后臺的內(nèi)存使用架谎,另一個是運行時的內(nèi)存使用炸宵。
procstats
2.Android 4.4 KitKat 提出了一個新系統(tǒng)服務(wù),叫做procstats狐树。它將幫助你更好的理解你app在后臺(background)時的內(nèi)存使用情況焙压。
可以通過adb shell命令去使用procstats(adb shell dumpsys procstats --hours 3),
或者更方便的方式是運行Process Stats開發(fā)者工具(在4.4版本的手機(jī)中點擊Settings > Developer options > Process Stats)

3.meminfo
Android還提供了一個工具叫做meminfo抑钟。它是根據(jù)PSS標(biāo)準(zhǔn) (Proportional Set Size——實際物理內(nèi)存)計算每個進(jìn)程的內(nèi)存使用并且按照重要程度排序涯曲。
你可以通過命令行去執(zhí)行它:(adb shell dumpsys meminfo)或者使用在設(shè)備上點擊Settings > Apps > Running(與Procstats不用,它也可以在老版本上運行)

命令查看內(nèi)存等

1.查看Dalvik內(nèi)存配置文件
adb pull /system/build.prop xxx 導(dǎo)入/system/build.prop到本地電腦

dalvik.vm.heapstartsize=8m
dalvik.vm.heapgrowthlimit=192m
dalvik.vm.heapsize=512m
dalvik.vm.heapstartsize=8m 相當(dāng)于虛擬機(jī)的 -Xms配置在塔,該項用來設(shè)置堆內(nèi)存的初始大小幻件。
dalvik.vm.heapgrowthlimit=192m 相當(dāng)于虛擬機(jī)的 -XX:HeapGrowthLimit配置,該項用來設(shè)置一個標(biāo)準(zhǔn)的應(yīng)用的最大堆內(nèi)存大小蛔溃。一個標(biāo)準(zhǔn)的應(yīng)用就是沒有使用android:largeHeap的應(yīng)用绰沥。
dalvik.vm.heapsize=512m 相當(dāng)于虛擬機(jī)的 -Xmx配置篱蝇,該項設(shè)置了使用android:largeHeap的應(yīng)用的最大堆內(nèi)存大小。

2.shell查看
adb shell getprop|grep dalvik.vm.heapstartsize 應(yīng)用啟動后分配的初始內(nèi)存(某機(jī)型無效)
adb shell getprop|grep heapgrowthlimit 單個標(biāo)準(zhǔn)應(yīng)用程序最大內(nèi)存限制(沒設(shè)置android:largeHeap)
adb shell getprop|grep dalvik.vm.heapsize 單個dalvik虛擬機(jī)最大的內(nèi)存限制(設(shè)置了android:largeHeap)

Heap(堆內(nèi)存):
在程序中可以使用如下的方法去查詢內(nèi)存使用情況

ActivityManager#getMemoryClass()

ActivityManager#getMemoryInfo(ActivityManager.MemoryInfo)
得到的MemoryInfo中可以查看如下Field的屬性:
availMem:表示系統(tǒng)剩余內(nèi)存
lowMemory:它是boolean值徽曲,表示系統(tǒng)是否處于低內(nèi)存運行
hreshold:它表示當(dāng)系統(tǒng)剩余內(nèi)存低于好多時就看成低內(nèi)存運行

android.os.Debug#getMemoryInfo(Debug.MemoryInfo memoryInfo)

dalvikPrivateDirty: The private dirty pages used by dalvik零截。
dalvikPss :The proportional set size for dalvik.
dalvikSharedDirty :The shared dirty pages used by dalvik.
nativePrivateDirty :The private dirty pages used by the native heap.
nativePss :The proportional set size for the native heap.
nativeSharedDirty :The shared dirty pages used by the native heap.
otherPrivateDirty :The private dirty pages used by everything else.
otherPss :The proportional set size for everything else.
otherSharedDirty :The shared dirty pages used by everything else.

說明:

dalvik:是指dalvik所使用的內(nèi)存。
native:是被native堆使用的內(nèi)存秃臣。應(yīng)該指使用C\C++在堆上分配的內(nèi)存涧衙。
other:是指除dalvik和native使用的內(nèi)存。但是具體是指什么呢奥此?至少包括在C\C++分配的非堆內(nèi)存弧哎,比如分配在棧上的內(nèi)存。
private:是指私有的稚虎。非共享的撤嫩。
share:是指共享的內(nèi)存。
PSS:實際使用的物理內(nèi)存(比例分配共享庫占用的內(nèi)存)
PrivateDirty:它是指非共享的蠢终,又不能換頁出去(can not be paged to disk )的內(nèi)存的大小序攘。比如Linux為了提高分配內(nèi)存速度而緩沖的小對象,即使你的進(jìn)程結(jié)束蜕径,該內(nèi)存也不會釋放掉两踏,它只是又重新回到緩沖中而已败京。
SharedDirty:參照PrivateDirty我認(rèn)為它應(yīng)該是指共享的兜喻,又不能換頁出去(can not be paged to disk )的內(nèi)存的大小。比如Linux為了提高分配內(nèi)存速度而緩沖的小對象赡麦,即使所有共享它的進(jìn)程結(jié)束朴皆,該內(nèi)存也不會釋放掉,它只是又重新回到緩沖中而已泛粹。

android.os.Debug#getNativeHeapSize()
返回的是當(dāng)前進(jìn)程navtive堆本身總的內(nèi)存大小
android.os.Debug#getNativeHeapAllocatedSize()
返回的是當(dāng)前進(jìn)程navtive堆中已使用的內(nèi)存大小
android.os.Debug#getNativeHeapFreeSize()
返回的是當(dāng)前進(jìn)程navtive堆中已經(jīng)剩余的內(nèi)存大小

技巧:android:largeHeap="true”(小心使用)

@@@@@@@@@@@@@@@@@@@@@@@@@@

需要特別注意優(yōu)化的點

1.Bitmap:

Bitmap是內(nèi)存消耗大戶遂铡,絕大多數(shù)的OOM崩潰都是在操作Bitmap時產(chǎn)生的,下面來看看如何幾個處理圖片的方法:

bitmap緩存:
內(nèi)存緩存(LruCache)
硬盤緩存(DiskLruCache)

根據(jù)需求去加載圖片的大小晶姊。

例如在列表中僅用于預(yù)覽時加載縮略圖(thumbnails )扒接。
只有當(dāng)用戶點擊具體條目想看詳細(xì)信息的時候,這時另啟動一個fragment/activity/對話框等等们衙,去顯示整個圖片

圖片大屑卣:
直接使用ImageView顯示bitmap會占用較多資源,特別是圖片較大的時候蒙挑,可能導(dǎo)致崩潰宗侦。
使用BitmapFactory.Options設(shè)置inSampleSize, 這樣做可以減少對系統(tǒng)資源的要求。
屬性值inSampleSize表示縮略圖大小為原始圖片大小的幾分之一忆蚀,即如果這個值為2矾利,則取出的縮略圖的寬和高都是原始圖片的1/2姑裂,圖片大小就為原始大小的1/4。

圖片像素:
Android中圖片有四種屬性男旗,分別是:
ALPHA_8:每個像素占用1byte內(nèi)存
ARGB_4444:每個像素占用2byte內(nèi)存
ARGB_8888:每個像素占用4byte內(nèi)存 (默認(rèn))
RGB_565:每個像素占用2byte內(nèi)存

Android默認(rèn)的顏色模式為ARGB_8888舶斧,這個顏色模式色彩最細(xì)膩,顯示質(zhì)量最高察皇。但同樣的捧毛,占用的內(nèi)存也最大。 所以在對圖片效果不是特別高的情況下使用RGB_565(565沒有透明度屬性)

圖片回收:

使用Bitmap過后让网,就需要及時的調(diào)用Bitmap.recycle()方法來釋放Bitmap占用的內(nèi)存空間呀忧,而不要等Android系統(tǒng)來進(jìn)行釋放。

捕獲異常:
經(jīng)過上面這些優(yōu)化后還會存在報OOM的風(fēng)險溃睹,所以下面需要一道最后的關(guān)卡——捕獲OOM異常:

2.強(qiáng)引用>軟引用>弱引用>虛引用

強(qiáng)引用(strong reference)
如:Object object=new Object()而账,object就是一個強(qiáng)引用了。當(dāng)內(nèi)存空間不足因篇,Java虛擬機(jī)寧愿拋出OutOfMemoryError錯誤泞辐,使程序異常終止,也不會靠隨意回收具有強(qiáng)引用的對象來解決內(nèi)存不足問題竞滓。
軟引用(SoftReference)
只有內(nèi)存不夠時才回收,常用于緩存咐吼;當(dāng)內(nèi)存達(dá)到一個閥值,GC就會去回收它商佑;

弱引用(WeakReference)
弱引用的對象擁有更短暫的生命周期锯茄。在垃圾回收器線程掃描它 所管轄的內(nèi)存區(qū)域的過程中,一旦發(fā)現(xiàn)了只具有弱引用的對象茶没,不管當(dāng)前內(nèi)存空間足夠與否肌幽,都會回收它的內(nèi)存。

虛引用(PhantomReference)
"虛引用"顧名思義抓半,就是形同虛設(shè)喂急,與其他幾種引用都不同,虛引用并不會決定對象的生命周期笛求。如果一個對象僅持有虛引用廊移,那么它就和沒有任何引用一樣,在任何時候都可能被垃圾回收探入。

3.縮小變量范圍

4.對常量使用static final修飾符

5.Context生命周期過長狡孔,

盡量避免static成員變量引用資源耗費過多的實例,
廣播
handler
toast

6避免創(chuàng)建不必要的對象

7.線程控制

8.UI Review(視圖檢查):

Android對于視圖中控件的布局渲染等會消耗很多的資源和內(nèi)存,所以這部分也是我們需要注意的新症。

減少視圖層級:
減少視圖層級可以有效的減少內(nèi)存消耗步氏,因為視圖是一個樹形結(jié)構(gòu),每次刷新和渲染都會遍歷一次徒爹。

hierarchyviewer:
想要減少視圖層級首先就需要知道視圖層級荚醒,所以下面介紹一個SDK中自帶的一個非常好用的工具h(yuǎn)ierarchyviewer芋类。
你可以在下面的地址找到它:your sdk path\sdk\tools

合理運用分屏,轉(zhuǎn)屏等

在視圖中加載你所需要的界阁,而不是你所擁有侯繁。因為用戶不可能同時看到所有東西。最典型的例子就是ListView中的滑動加載泡躯。

9.使用時再下載

====================恢復(fù)activity狀態(tài)

getLastNonConfigurationInstance贮竟,在oncreate或onstart里實例化,獲取onRetainNonConfigurationInstance中保存的實例

和onSaveInstanceState這個方法最大的好處是:
* 當(dāng)Activity曾經(jīng)通過某個資源得到一些圖片或者信息较剃,那么當(dāng)再次恢復(fù)后咕别,無需重新通過原始資源地址獲取,可以快速的加載整個Activity狀態(tài)信息写穴。
* 當(dāng)Activity包含有許多線程時惰拱,在變化后依然可以持有原有線程,無需通過重新創(chuàng)建進(jìn)程恢復(fù)原有狀態(tài)啊送。
* 當(dāng)Activity包含某些Connection Instance時,同樣可以在整個變化過程中保持連接狀態(tài)馋没。
注意:只做配置更改的優(yōu)化昔逗,依然要處理空指針的情況

下邊是需要特別注意的幾點:
1.使用有風(fēng)險
onRetainNonConfigurationInstance()
* The function will be called between {@link #onStop} and* {@link #onDestroy}.

如何加快應(yīng)用啟動速度

1.如果是6.0及以上,才考慮用閃屏篷朵。閃屏?xí)?00ms的優(yōu)化勾怒。
2.懶加載,針對不同客戶的加載款票。注意:防止集中化控硼,導(dǎo)致首頁加載后不可操作。
3.算法優(yōu)化艾少,
4.線程優(yōu)化,注意防止加鎖翼悴,導(dǎo)致線程阻塞缚够。一般用線程池管理線程○惺辏控制線程數(shù)谍椅,減少cpu調(diào)度,以及頻繁切換工作線程古话。
pipeline機(jī)制雏吭,根據(jù)業(yè)務(wù)優(yōu)先級定義業(yè)務(wù)初始化時機(jī)。為各個任務(wù)建立依賴,但是如果沒配置好腋妙,會導(dǎo)致主線程一直等待场躯。
注:參考框架:mmkernel套么、 alpha牵舵,
5.gc情況抖甘,debug結(jié)合allocation工具

Debug.startAllocCounting

6.啟動時盡量不要做系統(tǒng)調(diào)用爷绘,會占有cpu資源

Android崩潰入手

1.哪個進(jìn)程鲤屡、哪個線程孝治。是否主線程列粪,是前臺進(jìn)程,后臺進(jìn)程谈飒,還是系統(tǒng)進(jìn)程岂座。
2.是Java異常,native異常杭措,還是anr

關(guān)于性能的兩張圖掺逼。

以下圖片引自:https://time.geekbang.org/column/article/70250#previewimg

fb492a5ede709bbacb59953c04d986fb.png

211405b9dcf1291e1e1bb1fbfb2a70fd.jpeg.png

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市瓤介,隨后出現(xiàn)的幾起案子吕喘,更是在濱河造成了極大的恐慌,老刑警劉巖刑桑,帶你破解...
    沈念sama閱讀 211,123評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件氯质,死亡現(xiàn)場離奇詭異,居然都是意外死亡祠斧,警方通過查閱死者的電腦和手機(jī)闻察,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,031評論 2 384
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來琢锋,“玉大人辕漂,你說我怎么就攤上這事∥獬” “怎么了钉嘹?”我有些...
    開封第一講書人閱讀 156,723評論 0 345
  • 文/不壞的土叔 我叫張陵,是天一觀的道長鲸阻。 經(jīng)常有香客問我跋涣,道長,這世上最難降的妖魔是什么鸟悴? 我笑而不...
    開封第一講書人閱讀 56,357評論 1 283
  • 正文 為了忘掉前任陈辱,我火速辦了婚禮,結(jié)果婚禮上细诸,老公的妹妹穿的比我還像新娘沛贪。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 65,412評論 5 384
  • 文/花漫 我一把揭開白布利赋。 她就那樣靜靜地躺著水评,像睡著了一般。 火紅的嫁衣襯著肌膚如雪隐砸。 梳的紋絲不亂的頭發(fā)上之碗,一...
    開封第一講書人閱讀 49,760評論 1 289
  • 那天,我揣著相機(jī)與錄音季希,去河邊找鬼褪那。 笑死,一個胖子當(dāng)著我的面吹牛式塌,可吹牛的內(nèi)容都是我干的博敬。 我是一名探鬼主播,決...
    沈念sama閱讀 38,904評論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼峰尝,長吁一口氣:“原來是場噩夢啊……” “哼偏窝!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起武学,我...
    開封第一講書人閱讀 37,672評論 0 266
  • 序言:老撾萬榮一對情侶失蹤祭往,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后火窒,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體硼补,經(jīng)...
    沈念sama閱讀 44,118評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,456評論 2 325
  • 正文 我和宋清朗相戀三年熏矿,在試婚紗的時候發(fā)現(xiàn)自己被綠了已骇。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,599評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡票编,死狀恐怖褪储,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情慧域,我是刑警寧澤鲤竹,帶...
    沈念sama閱讀 34,264評論 4 328
  • 正文 年R本政府宣布,位于F島的核電站吊趾,受9級特大地震影響宛裕,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜论泛,卻給世界環(huán)境...
    茶點故事閱讀 39,857評論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望蛹屿。 院中可真熱鬧屁奏,春花似錦、人聲如沸错负。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,731評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至折联,卻和暖如春粒褒,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背诚镰。 一陣腳步聲響...
    開封第一講書人閱讀 31,956評論 1 264
  • 我被黑心中介騙來泰國打工奕坟, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人清笨。 一個月前我還...
    沈念sama閱讀 46,286評論 2 360
  • 正文 我出身青樓月杉,卻偏偏與公主長得像,于是被迫代替她去往敵國和親抠艾。 傳聞我的和親對象是個殘疾皇子苛萎,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,465評論 2 348

推薦閱讀更多精彩內(nèi)容