Android異常與性能優(yōu)化問題

一、ANR(Application Not Responding)問題

1、什么是ANR(Application Not Responding)
ANR就是一個(gè)程序無響應(yīng)的對(duì)話框

在一個(gè)Activity(Service)當(dāng)中最長(zhǎng)的執(zhí)行時(shí)間是5秒泳挥,超出5秒無響應(yīng)就會(huì)導(dǎo)致ANR
在一個(gè)BroadcastReceiver當(dāng)中最長(zhǎng)的執(zhí)行時(shí)間是10秒,
原因:在主線程中做了耗時(shí)操作,所以才會(huì)導(dǎo)致ANR的彈框

2、造成ANR的主要原因

應(yīng)用程序的響應(yīng)性是由Activity Manager和WindowManager系統(tǒng)服務(wù)監(jiān)視的太伊,當(dāng)它監(jiān)測(cè)到Activity和BroadcastReceiver當(dāng)中5秒、10秒沒有執(zhí)行完任務(wù)之后逛钻。安卓就會(huì)彈出ANR的對(duì)話框

  • 主線程被IO操作(從4.0之后網(wǎng)絡(luò)IO不允許在主線程中)阻塞
  • 主線程中存在耗時(shí)操作
3僚焦、造成ANR的主要原因-Android中哪些操作是在主線程呢?
  • Activity的所有生命周期回調(diào)都是執(zhí)行在主線程的
  • Service默認(rèn)是執(zhí)行在主線程的
  • BroadcastReceiver的onReceive回調(diào)是執(zhí)行在主線程的
  • 沒有使用子線程的looper的Handler的handlerMessage曙痘,post(Runnable)是執(zhí)行在主線程的
  • AsyncTask的回調(diào)中除了doInBackground芳悲,其他都是執(zhí)行在主線程
4、如何解決ANR
  • 使用AsyncTask處理耗時(shí)IO操作
  • 使用Thread或者HandlerThread提高優(yōu)先級(jí)边坤,不提高優(yōu)先級(jí) 它的優(yōu)先級(jí)和主線程的優(yōu)先級(jí)是一樣的仍然會(huì)造成ANR
  • 使用handler來處理工作線程的耗時(shí)任務(wù)
  • 在Activity的onCreate和onResume回調(diào)中盡量避免耗時(shí)的操作

二名扛、OOM(Out of Memory)問題

1、什么是oom

當(dāng)前占用的內(nèi)存加上我們申請(qǐng)的內(nèi)存資源超過了Dalvik虛擬機(jī)的最大內(nèi)存限制就會(huì)拋出Out of memory異常惩嘉,最常見的oom就是bitmap加載大圖的時(shí)候罢洲。

2、一些容易混淆的概念
  • 內(nèi)存溢出:就是Out of memory
  • 內(nèi)存抖動(dòng):短時(shí)間內(nèi)大量的對(duì)象被創(chuàng)建又被馬上釋放文黎,瞬間產(chǎn)生的對(duì)象。會(huì)嚴(yán)重占用內(nèi)存區(qū)域
  • 內(nèi)存泄露:進(jìn)程中的某些對(duì)象殿较,比如說垃圾對(duì)象耸峭。已經(jīng)沒有被其他對(duì)象引用到了,但是它們確可以直接或間接引用到GCRoots淋纲。導(dǎo)致GC無法直接產(chǎn)生作用劳闹,一旦內(nèi)存泄露累積到一定程度,就會(huì)引起內(nèi)存溢出。
3本涕、如何解決oom

1业汰、有關(guān)bitmap優(yōu)化

  • 圖片的顯示:比如ListView滑動(dòng)的時(shí)候要顯示縮略圖不要去網(wǎng)絡(luò)請(qǐng)求下載圖片,只有監(jiān)聽到ListView停止滑動(dòng)的時(shí)候再去加載網(wǎng)絡(luò)大圖
  • 及時(shí)釋放內(nèi)存
  • 圖片壓縮
  • inBitmap屬性
  • 捕獲異常

2菩颖、ListView

  • ConverView/Lru機(jī)制緩存bitmap
  • 避免在onDraw方法里面執(zhí)行對(duì)象的創(chuàng)建样漆,頻繁的創(chuàng)建對(duì)象容易引起內(nèi)存抖動(dòng)
  • 謹(jǐn)慎使用多進(jìn)程

三、Bitmap相關(guān)問題

bitmap是存在native內(nèi)存和Java內(nèi)存當(dāng)中的晦闰,當(dāng)被回收的時(shí)候分兩部分回收放祟。一是回收J(rèn)ava內(nèi)存當(dāng)中的內(nèi)存二是回收native內(nèi)存當(dāng)中的內(nèi)存。
1呻右、Recycle

recycle釋放bitmap內(nèi)存的時(shí)候跪妥,會(huì)釋放和這個(gè)bitmap有關(guān)的native內(nèi)存,同時(shí)會(huì)清理有關(guān)數(shù)據(jù)對(duì)象的引用声滥。但不是立即清理眉撵,它會(huì)給垃圾回收器發(fā)送消息指令。讓它在沒有其他對(duì)象引用這個(gè)bitmap對(duì)象的時(shí)候落塑,進(jìn)行垃圾回收纽疟。
當(dāng)bitmap調(diào)用recycle之后,bitmap會(huì)被標(biāo)記為“dead”芜赌。這個(gè)時(shí)候你再調(diào)用bitmap的其他方法就會(huì)引起異常仰挣。比如getPixels()或者setPixels(),同時(shí)recycle操作是不可逆的。所以你要確定被recycle之后不再調(diào)用這個(gè)bitmap對(duì)象以及它的任何方法缠沈,否則就會(huì)引起異常膘壶。官方建議我們不主動(dòng)調(diào)用recycle方法,當(dāng)沒有對(duì)象引用這個(gè)bitmap的時(shí)候垃圾回收器會(huì)主動(dòng)的回收這個(gè)對(duì)象洲愤。

2颓芭、LRU算法
  • lru算法是最近最少使用的對(duì)象,我們把它清除出緩存隊(duì)列柬赐。
  • LruCache是一個(gè)泛型類亡问,lru算法內(nèi)部使用了一個(gè)LinkedHashMap來實(shí)現(xiàn)的,并且提供了get和put方法來完成緩存的添加和獲取操作肛宋,當(dāng)緩存滿的時(shí)候它內(nèi)部提供了一個(gè)trimToSize()的方法州藕。把較早和最少使用的的緩存對(duì)象移除并添加新的緩存對(duì)象。
3酝陈、計(jì)算inSampleSize
// 根據(jù)maxWidth, maxHeight計(jì)算最合適的inSampleSize
    public static int calculateInSampleSize(
            BitmapFactory.Options options, int reqWidth, int reqHeight) {
        // 圖像的原始高度和寬度
        final int height = options.outHeight;
        final int width = options.outWidth;
        int inSampleSize = 1;

        if (height > reqHeight || width > reqWidth) {
            if (width > height) {
                inSampleSize = Math.round((float)height / (float)reqHeight);
            } else {
                inSampleSize = Math.round((float)width / (float)reqWidth);
            }
        }
        return inSampleSize;
    }
4床玻、縮略圖
//縮略圖
    public static Bitmap thumbnail(String path,
                                   int maxWidth, int maxHeight, boolean autoRotate) {
        BitmapFactory.Options options = new BitmapFactory.Options();
        options.inJustDecodeBounds = true;
        // 獲取這個(gè)圖片的寬和高信息到options中, 此時(shí)返回bm為空
        Bitmap bitmap = BitmapFactory.decodeFile(path, options);
        options.inJustDecodeBounds = false;
        // 計(jì)算縮放比
        int sampleSize = calculateInSampleSize(options, maxWidth, maxHeight);
        options.inSampleSize = sampleSize;
        options.inPreferredConfig = Bitmap.Config.RGB_565;
        options.inPurgeable = true;
        options.inInputShareable = true;
        if (bitmap != null && !bitmap.isRecycled()) {
            bitmap.recycle();
        }
        bitmap = BitmapFactory.decodeFile(path, options);
        return bitmap;
    }
5、三級(jí)緩存
  • 網(wǎng)絡(luò)緩存
  • 本地緩存
  • 內(nèi)存緩存

四沉帮、UI卡頓問題

1锈死、UI卡頓原理

UI渲染系統(tǒng)做了太多的耗時(shí)操作贫堰,和執(zhí)行了大量的動(dòng)畫。
60fps->16ms
過渡繪制:UI布局中有大量重疊的部分待牵,多層次的UI結(jié)構(gòu)中其屏。

2.UI卡頓的原因分析
  • 人為在UI線程中做輕微耗時(shí)操作,導(dǎo)致UI線程卡頓
  • 布局Layout過于復(fù)雜缨该,無法在16ms內(nèi)完成渲染
  • 同一時(shí)間動(dòng)畫執(zhí)行的次數(shù)過多偎行,導(dǎo)致CPU或GPU負(fù)載過重
  • View過渡繪制,導(dǎo)致某些像素在同一幀時(shí)間內(nèi)被繪制多次压彭,從而使CPU或GPU負(fù)載過重
  • View頻繁的觸發(fā)measure睦优、layout,導(dǎo)致measure壮不、layout累計(jì)耗時(shí)過多及整個(gè)View頻繁的重新渲染
  • 內(nèi)存頻繁觸發(fā)GC過多汗盘,導(dǎo)致暫時(shí)阻塞渲染操作
  • 冗余資源及邏輯等導(dǎo)致加載和執(zhí)行緩慢
  • ANR
3、UI卡頓總結(jié)
  • 布局優(yōu)化:使用常見的include询一、merge隐孽、ViewStub標(biāo)簽。盡量不存在冗余嵌套或者復(fù)雜的布局
  • 列表及Adapter優(yōu)化
  • 背景和圖片等內(nèi)存分配優(yōu)化
  • 避免ANR

五健蕊、內(nèi)存泄露問題

1蝗砾、java內(nèi)存的分配策略
  • 靜態(tài)存儲(chǔ)區(qū)(方法區(qū))
    存放靜態(tài)數(shù)據(jù)缔赠、全局變量聂宾。程序編譯的時(shí)候已經(jīng)分配好了箫章,在靜態(tài)存儲(chǔ)區(qū)存儲(chǔ)的變量,在程序運(yùn)行的整個(gè)期間都會(huì)存在
  • 棧區(qū)
    方法內(nèi)的局部變量嫡锌,會(huì)在棧上創(chuàng)建存儲(chǔ)空間虑稼。并在方法結(jié)束后,這些在變量所持有的內(nèi)存會(huì)被自動(dòng)釋放
  • 堆區(qū)
    又稱動(dòng)態(tài)內(nèi)存分配势木,通常就是我們new對(duì)象出來的內(nèi)存蛛倦。這部分內(nèi)存在不使用的時(shí)候會(huì)有java的內(nèi)存回收器進(jìn)行回收
2、java中的內(nèi)存泄露

內(nèi)存泄露是指無用對(duì)象(不再使用的對(duì)象)持續(xù)占有內(nèi)存或無用對(duì)象的內(nèi)存得不到及時(shí)釋放啦桌,從而造成的內(nèi)存空間的浪費(fèi)稱為內(nèi)存泄露溯壶。

六、Android內(nèi)存管理機(jī)制

1甫男、分配機(jī)制

操作系統(tǒng)會(huì)為每個(gè)進(jìn)程分配一個(gè)合理大小的內(nèi)存且改,從而保證每一個(gè)進(jìn)程能夠正常的運(yùn)行。而不至于內(nèi)存不夠使用或者每個(gè)進(jìn)程占用太多的內(nèi)存

2板驳、回收機(jī)制

在系統(tǒng)內(nèi)存不夠的時(shí)候钾虐,他會(huì)有一個(gè)合理的回收再分配機(jī)制從而保證新的進(jìn)程能夠正常的運(yùn)行。

3笋庄、內(nèi)存管理機(jī)制的特點(diǎn)
  • 更少的占用內(nèi)存
  • 在合適的時(shí)候效扫,合理的釋放系統(tǒng)資源
  • 在系統(tǒng)內(nèi)存緊張的情況下,能釋放大部分不重要的資源直砂,來為Android系統(tǒng)提供可用的內(nèi)存
  • 能夠很合理的在特殊生命周期菌仁,保存或者還原重要數(shù)據(jù),以至于系統(tǒng)能夠保證正確的重新恢復(fù)該應(yīng)用
4静暂、內(nèi)存優(yōu)化的方法
  • 當(dāng)Service完成任務(wù)后济丘,盡量停止它。推薦使用Intentservice
  • 在UI不可見的時(shí)候洽蛀,釋放掉一些只有UI使用的資源
  • 在系統(tǒng)內(nèi)存緊張的時(shí)候摹迷,盡可能多的釋放掉一些非重要資源
  • 避免濫用Bitmap導(dǎo)致的內(nèi)存浪費(fèi)
  • 使用針對(duì)內(nèi)存優(yōu)化過的數(shù)據(jù)容器:SparseArray
  • 避免使用依賴注入的框架
  • 使用ZIP對(duì)齊的APK
  • 使用多進(jìn)程

七、冷啟動(dòng)優(yōu)化

1郊供、冷啟動(dòng)的定義

冷啟動(dòng)就是在啟動(dòng)應(yīng)用前峡碉,系統(tǒng)中沒有該應(yīng)用的任何進(jìn)程信息

2、冷啟動(dòng)和熱啟動(dòng)的區(qū)別

熱啟動(dòng):用戶使用返回鍵退出應(yīng)用驮审,然后馬上又重新啟動(dòng)應(yīng)用鲫寄。熱啟動(dòng)的應(yīng)用的進(jìn)程是保留在后臺(tái)的

  • 冷啟動(dòng):每次啟動(dòng)的時(shí)候都會(huì)走Application這個(gè)類,
  • 熱啟動(dòng):進(jìn)程中保留留這個(gè)app的進(jìn)行疯淫,它會(huì)直接走M(jìn)ainActivity這個(gè)類
3地来、冷啟動(dòng)的流程
  • Zygote進(jìn)程中fork創(chuàng)建出一個(gè)新的進(jìn)程
  • 創(chuàng)建和初始化Application類、創(chuàng)建MainActivity類inflate布局
  • 當(dāng)onCreate/onStart/onResume方法都走完
  • contentView的measure/layout/draw顯示在界面上
4熙掺、冷啟動(dòng)流程-總結(jié)

Application的構(gòu)造方法->attachBaseContext()->onCreate()->Activity的構(gòu)造方法->onCreate()->配置主題中背景等屬性->onStart()->onResume()->測(cè)量布局繪制顯示在界面上

5未斑、 如何對(duì)冷啟動(dòng)的時(shí)間進(jìn)行優(yōu)化
  • 減少onCreate()方法的工作量
  • 不要讓Application參與業(yè)務(wù)的操作
  • 不要在Application進(jìn)行耗時(shí)操作
  • 不要以靜態(tài)變量的方式在Application中保存數(shù)據(jù)
  • 布局(減少布局的復(fù)雜性)、mainThread(資源的初始化放到子線程當(dāng)中)

八币绩、其他優(yōu)化問題

1蜡秽、Android不用靜態(tài)變量?jī)?chǔ)存數(shù)據(jù)
  • 靜態(tài)變量等數(shù)據(jù)由于進(jìn)程已經(jīng)被殺死而被從新初始化
  • 使用其他數(shù)據(jù)傳輸方式:文件、SP类浪、contentProvider,要對(duì)數(shù)據(jù)進(jìn)行非空判斷
2载城、有關(guān)SharePreference問題
  • 不能跨進(jìn)程同步
  • 存儲(chǔ)SharePreference的文件過大問題,文件過大獲取值得時(shí)候费就,有可能阻塞主線程诉瓦。解析很大的SharePreference文件的時(shí)候會(huì)產(chǎn)生大量的臨時(shí)文件對(duì)象,導(dǎo)致垃圾回收機(jī)制頻繁的進(jìn)行垃圾回收力细。容易造成UI卡頓和內(nèi)存抖動(dòng)
3睬澡、內(nèi)存對(duì)象的序列化

序列化:將對(duì)象的狀態(tài)信息轉(zhuǎn)換為可以儲(chǔ)存或傳輸?shù)男问降倪^程

  • Serializeble:Serializeble在序列化的時(shí)候會(huì)產(chǎn)生大量的臨時(shí)變量,從而引起頻繁的垃圾回收眠蚂。影響UI卡頓煞聪,容易引起內(nèi)存抖動(dòng),造成oom
  • Parcelable:不能使用存儲(chǔ)在磁盤上的文件
4逝慧、 內(nèi)存對(duì)象序列化-總結(jié)
  • Serializeble是java的序列化方式昔脯,Parcelable是Android特有的序列化方式
  • 在使用內(nèi)存的時(shí)候啄糙,Parcelable比Serializeble性能高
  • Serializeble在序列化的時(shí)候會(huì)產(chǎn)生大量的臨時(shí)變量,從而引起頻繁的GC
  • Parcelable不能使用在要將數(shù)據(jù)存儲(chǔ)在磁盤上的情況

推薦使用Serializeble進(jìn)行數(shù)據(jù)序列化

避免在UI線程中做繁重的操作

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末云稚,一起剝皮案震驚了整個(gè)濱河市隧饼,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌静陈,老刑警劉巖燕雁,帶你破解...
    沈念sama閱讀 222,627評(píng)論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異鲸拥,居然都是意外死亡拐格,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,180評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門刑赶,熙熙樓的掌柜王于貴愁眉苦臉地迎上來捏浊,“玉大人,你說我怎么就攤上這事角撞∏喊椋” “怎么了?”我有些...
    開封第一講書人閱讀 169,346評(píng)論 0 362
  • 文/不壞的土叔 我叫張陵谒所,是天一觀的道長(zhǎng)热康。 經(jīng)常有香客問我,道長(zhǎng)劣领,這世上最難降的妖魔是什么姐军? 我笑而不...
    開封第一講書人閱讀 60,097評(píng)論 1 300
  • 正文 為了忘掉前任,我火速辦了婚禮尖淘,結(jié)果婚禮上奕锌,老公的妹妹穿的比我還像新娘。我一直安慰自己村生,他們只是感情好惊暴,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,100評(píng)論 6 398
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著趁桃,像睡著了一般辽话。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上卫病,一...
    開封第一講書人閱讀 52,696評(píng)論 1 312
  • 那天油啤,我揣著相機(jī)與錄音,去河邊找鬼蟀苛。 笑死益咬,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的帜平。 我是一名探鬼主播幽告,決...
    沈念sama閱讀 41,165評(píng)論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼梅鹦,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了评腺?” 一聲冷哼從身側(cè)響起帘瞭,我...
    開封第一講書人閱讀 40,108評(píng)論 0 277
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎蒿讥,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體抛腕,經(jīng)...
    沈念sama閱讀 46,646評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡芋绸,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,709評(píng)論 3 342
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了担敌。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片摔敛。...
    茶點(diǎn)故事閱讀 40,861評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖全封,靈堂內(nèi)的尸體忽然破棺而出马昙,到底是詐尸還是另有隱情,我是刑警寧澤刹悴,帶...
    沈念sama閱讀 36,527評(píng)論 5 351
  • 正文 年R本政府宣布行楞,位于F島的核電站,受9級(jí)特大地震影響土匀,放射性物質(zhì)發(fā)生泄漏子房。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,196評(píng)論 3 336
  • 文/蒙蒙 一就轧、第九天 我趴在偏房一處隱蔽的房頂上張望证杭。 院中可真熱鬧,春花似錦妒御、人聲如沸解愤。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,698評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽送讲。三九已至,卻和暖如春梦鉴,著一層夾襖步出監(jiān)牢的瞬間李茫,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,804評(píng)論 1 274
  • 我被黑心中介騙來泰國(guó)打工肥橙, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留魄宏,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 49,287評(píng)論 3 379
  • 正文 我出身青樓存筏,卻偏偏與公主長(zhǎng)得像宠互,于是被迫代替她去往敵國(guó)和親味榛。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,860評(píng)論 2 361

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