前言
內(nèi)存問題是一個普遍問題,但是卻普遍缺少關(guān)注度,具體有以下幾個原因:
內(nèi)存問題相對比較隱蔽,表現(xiàn)并不明顯。
同時android使用Jvm語言開發(fā),垃圾回收是自動的,所以一般沒有特別關(guān)注。
內(nèi)存問題難以定位,出現(xiàn)問題的地方往往只是表現(xiàn)的地方,真正的原因難以收集。
內(nèi)存優(yōu)化的內(nèi)容其實非常多而復(fù)雜,我們可以嘗試從以下思路去了解:
要了解內(nèi)存問題,我們首先要了解為什么要做內(nèi)存優(yōu)化?
同時需要了解一些內(nèi)存優(yōu)化的背景知識,如垃圾回收機(jī)制。
我們需要了解一些內(nèi)存優(yōu)化的常用工具與手段。
圖片是內(nèi)存優(yōu)化的重點,我們需要重點了解下圖片優(yōu)化的知識點。
內(nèi)存問題的一個直接體現(xiàn)是OOM,我們還需要了解下OOM治理的一些手段。
所以我們可以輕松得出本文的主要內(nèi)容:
為什么要做內(nèi)存優(yōu)化?
android內(nèi)存優(yōu)化的一些背景知識。
android內(nèi)存優(yōu)化的常用工具與手段。
怎么做圖片內(nèi)存優(yōu)化?
怎么做OOM線上監(jiān)控?
本文主要內(nèi)容思維導(dǎo)圖如下:
1、為什么要做內(nèi)存優(yōu)化?
要回答這個問題,我們首先應(yīng)該明確需求,當(dāng)我們?nèi)プ鰞?nèi)存優(yōu)化時是為了什么。
做內(nèi)存優(yōu)化的目的是降低OOM率、減少卡頓、增加應(yīng)用存活時間。
1.1 降低OOM率
做內(nèi)存優(yōu)化的一個常見原因是為了降低OOM率。
申請內(nèi)存過多而沒有及時釋放,常常就會導(dǎo)致OOM。
引起OOM的原因有多種,在后面我們再細(xì)談。
1.2 減少卡頓
Android中造成界面卡頓的原因有很多種,其中一種就是由內(nèi)存問題引起的。
內(nèi)存問題之所以會影響到界面流暢度,是因為垃圾回收。
在GC時,所有線程都要停止,包括主線程。當(dāng)GC和繪制界面的操作同時觸發(fā)時,繪制的執(zhí)行就會被擱置,導(dǎo)致掉幀,也就是界面卡頓。
1.3 增加應(yīng)用存活時間
Android會按照特定的機(jī)制清理進(jìn)程,清理進(jìn)程時優(yōu)先會考慮清理后臺進(jìn)程,如果某個應(yīng)用在后臺運行并且占用的內(nèi)存更多,就會被優(yōu)先清理掉。
我們通常希望App能盡量存活的久一點,所以內(nèi)存不再使用時應(yīng)該盡快釋放。
2、android內(nèi)存優(yōu)化的一些背景知識
2.1 Java垃圾回收機(jī)制
Java內(nèi)存回收主要包括以下內(nèi)容:
判斷對象是否回收的可達(dá)性分析算法。
強(qiáng)軟弱虛4種引用類型。
用于GC回收的垃圾回收算法。
這些都是很常見的知識點了,這里也就不綴述了,如果想要了解更多細(xì)節(jié)的同學(xué)可參考:Java 垃圾回收機(jī)制。
https://juejin.cn/post/6844903897958449166
2.2 什么是內(nèi)存泄漏?
內(nèi)存泄漏指的是一塊內(nèi)存沒有被使用且無法被GC回收,從而造成了內(nèi)存的浪費,比如Handler匿名內(nèi)部類持有Activity的引用,Activity 需要銷毀時,GC 就無法回收它。
內(nèi)存泄漏的表現(xiàn)就是可用內(nèi)存逐漸減少,無法被回收的內(nèi)存逐漸累積,直到應(yīng)用無更多可用內(nèi)存可申請時,就會導(dǎo)致內(nèi)存溢出。
內(nèi)存泄漏的直接原因是長生命周期的對象引用了短生命周期的對象,導(dǎo)致短生命周期對象無法回收。
常見的引起內(nèi)存泄漏的原因有:
非靜態(tài)內(nèi)部類持有了外部引用。
靜態(tài)變量持有了context的引用。
資源沒有及時釋放。
我們一般使用LeakCanary或者Profile檢測內(nèi)存泄漏。
2.3 什么是內(nèi)存抖動?
當(dāng)我們在短時間內(nèi)頻繁創(chuàng)建大量臨時對象時,就會引起內(nèi)存抖動,比如在一個for循環(huán)中創(chuàng)建臨時對象實例,下面這張圖就是內(nèi)存抖動時的一個內(nèi)存圖表現(xiàn),它的形狀是鋸齒形的,而中間的垃圾桶代表著一次GC。
內(nèi)存抖動意味著頻繁的創(chuàng)建對象與回收,容易觸發(fā)GC,而當(dāng)GC時所有線程都會停止,因此可能導(dǎo)致卡頓。
為了避免內(nèi)存抖動,我們應(yīng)該避免以下操作:
盡量避免在循環(huán)體中創(chuàng)建對象。
盡量不要在自定義View的onDraw()方法中創(chuàng)建對象,因為這個方法會被頻繁調(diào)用。
對于能夠復(fù)用的對象,可以考慮使用對象池把它們緩存起來。
2.4 什么是內(nèi)存溢出?
內(nèi)存溢出即申請的內(nèi)存超出可用的內(nèi)存,即OOM,這會導(dǎo)致我們的程序異常退出,這也是我們重點關(guān)注的指標(biāo)。
引起OOM的原因可能有多種,主要可以分為以下幾類:
關(guān)于OOM治理及線上監(jiān)控等,后面會詳細(xì)介紹。
3、android內(nèi)存優(yōu)化的常用工具與手段
3.1 Memory Profiler
Memory Profiler是Profiler 中的其中一個版塊,Profiler 是 Android Studio 為我們提供的性能分析工具,使用 Profiler 能分析應(yīng)用的 CPU、內(nèi)存、網(wǎng)絡(luò)以及電量的使用情況。
使用Memory可以檢測以下功能:
查看內(nèi)存曲線及內(nèi)存占用情況。
可以定位是否存在內(nèi)存抖動問題。
堆轉(zhuǎn)儲(Dump Java Heap)可檢測出內(nèi)存泄漏的對象。
關(guān)于Memory Profiler的具體使用就不在此綴述了,想要了解的可參考:什么是 Memory Profiler?
https://juejin.cn/post/6844903897958449166
3.2 Memory Analyzer Tool
MAT工具可以幫助開發(fā)者定位導(dǎo)致內(nèi)存泄漏的對象,以及發(fā)現(xiàn)大的內(nèi)存對象,然后解決內(nèi)存泄漏并通過優(yōu)化內(nèi)存對象,以達(dá)到減少內(nèi)存消耗的目的。
比起Memory Profiler,MAT使用起來更加麻煩,同時現(xiàn)在Memory Profiler功能也越來越強(qiáng)大了,所以我現(xiàn)在已經(jīng)很少使用MAT了。
如果想要更多地了解MAT,也可以參考:什么是Memory Analyzer Tool。
https://juejin.cn/post/6844903897958449166#heading-52
3.3 LeakCanary檢測內(nèi)存泄漏
相比Memory Profiler與MAT,LeakCanary在使用上更加簡便。
只需要在項目中添加依賴,即可自動地檢測內(nèi)存泄漏并報警,使用起來非常方便。
LeakCanary有以下幾個特點:
不需要手動初始化。
可自動檢測內(nèi)存泄漏并通過通知報警。
不能用于線上。
LeakCanary檢測流程如下
關(guān)于LeakCanary的原理,我之前曾經(jīng)總結(jié)過一篇文章,有興趣的同學(xué)也可以參考:【帶著問題學(xué)】關(guān)于LeakCanary2.0你應(yīng)該知道的知識點。
https://juejin.cn/post/6968084138125590541
3.4 內(nèi)存優(yōu)化的一些常規(guī)手段
內(nèi)存優(yōu)化的一些細(xì)節(jié)問題可以在開發(fā)時避免,下面介紹一些常規(guī)的內(nèi)存優(yōu)化手段。
1)、使用LargeHeap屬性增加最大可用內(nèi)存。
2)、在系統(tǒng)觸發(fā)資源緊張回調(diào)時,主動刪除緩存。
3)、使用優(yōu)化過后的集合:如SparseArray類等。
4)、謹(jǐn)慎使用 SharedPreference,SP會在應(yīng)用初始化時將所有內(nèi)容加載到內(nèi)存中,所以不應(yīng)該存放比較大的內(nèi)容。
5)、謹(jǐn)慎使用外部庫,引入時需要明確不會對應(yīng)用性能造成大的影響。
6)、業(yè)務(wù)架構(gòu)設(shè)計要合理,抽象可以優(yōu)化代碼的靈活性和可維護(hù)性,但是抽象也會帶來其他成本,應(yīng)權(quán)衡使用。
這些細(xì)節(jié)問題其實都很普通,如果平時注意到了,相信對應(yīng)用的內(nèi)存一定有所幫助。
4、怎么做圖片內(nèi)存優(yōu)化?
內(nèi)存優(yōu)化應(yīng)該優(yōu)先去做見效快的地方,圖片內(nèi)存優(yōu)化是內(nèi)存優(yōu)化的重點,可能一張圖片沒有回收就會造成幾M內(nèi)存的浪費。
4.1 常規(guī)的圖片內(nèi)存優(yōu)化方法
我們都知道,圖片所占內(nèi)存=寬高一像素占用內(nèi)存。
所以優(yōu)化圖片內(nèi)存主要有以下幾個思路:
縮放減小寬高。
減少每個像素所占用的內(nèi)存。
內(nèi)存復(fù)用,避免重復(fù)分配內(nèi)存。
對于大圖,可以采取局部加載的策略。
4.1.1 減少圖片寬高
有時圖片寬高為200*200, 而View寬高為100*100, 這種時候如果展示200*200的圖片沒有意義,應(yīng)該對圖片進(jìn)行縮放。
這種情況一般通過inSampleSize實現(xiàn)。
BitampFactory.Options options = new BitmapFactory.Options();
// 設(shè)置為4就是寬和高都變?yōu)樵瓉?/4大小的圖片
options.inSampleSize = 4;
BitmapFactory.decodeSream(is, null, options);
4.1.2 減少每個像素所占用的內(nèi)存
在API29中,將Bitmap分為ALPHA_8, RGB_565, ARGB_4444, ARGB_8888, RGBA_F16, HARDWARE六個等級。
ALPHA_8:不存儲顏色信息,每個像素占1個字節(jié);
RGB_565:僅存儲RGB通道,每個像素占2個字節(jié),對Bitmap色彩沒有高要求,可以使用該模式;
ARGB_4444:已棄用,用ARGB_8888代替;
ARGB_8888:每個像素占用4個字節(jié),保持高質(zhì)量的色彩保真度,默認(rèn)使用該模式;
RGBA_F16:每個像素占用8個字節(jié),適合寬色域和HDR;
HARDWARE:一種特殊的配置,減少了內(nèi)存占用同時也加快了Bitmap的繪制。
每個等級每個像素所占用的字節(jié)也都不一樣,所存儲的色彩信息也不同。同一張100像素的圖片,ARGB_8888就占了400字節(jié),RGB_565才占200字節(jié)。
所以在某些場景中,修改圖片格式可以達(dá)到減少一半內(nèi)存的效果。
4.1.3 內(nèi)存復(fù)用,避免重復(fù)分配內(nèi)存
Bitmap所占內(nèi)存比較大,如果我們頻繁創(chuàng)建與回收Bitmap,那么很容易造成內(nèi)存抖動,所以我們應(yīng)該盡量復(fù)用Bitmap內(nèi)存。
在 Android 3.0(API 級別 11)開始,系統(tǒng)引入了BitmapFactory.Options.inBitmap字段。如果設(shè)置了此選項,那么采用 Options 對象的解碼方法會在生成目標(biāo) Bitmap 時嘗試復(fù)用 inBitmap,這意味著 inBitmap 的內(nèi)存得到了重復(fù)使用,從而提高了性能,同時移除了內(nèi)存分配和取消分配。
不過 inBitmap 的使用方式存在某些限制,在 Android 4.4(API 級別 19)之前系統(tǒng)僅支持復(fù)用大小相同的位圖,4.4 之后只要 inBitmap 的大小比目標(biāo) Bitmap 大即可。
4.1.4 大圖局部加載策略
對于圖片加載還有種情況,就是單個圖片非常巨大,并且還不允許壓縮。比如顯示:世界地圖、清明上河圖、微博長圖等。
首先不壓縮,按照原圖尺寸加載,那么屏幕肯定是不夠大的,并且考慮到內(nèi)存的情況,不可能一次性整圖加載到內(nèi)存中。
所以這種情況的優(yōu)化思路一般是局部加載,通過BitmapRegionDecoder來實現(xiàn)。
//設(shè)置顯示圖片的中心區(qū)域
BitmapRegionDecoder bitmapRegionDecoder = BitmapRegionDecoder.newInstance(inputStream, false);
BitmapFactory.Options options = new BitmapFactory.Options();
options.inPreferredConfig = Bitmap.Config.RGB_565;
Bitmap bitmap = bitmapRegionDecoder.decodeRegion(new Rect(width / 2 - 100, height / 2 - 100, width / 2 + 100, height / 2 + 100), options);
mImageView.setImageBitmap(bitmap);
4.1.5 小結(jié)
上面所說的這些關(guān)于Bitmap的內(nèi)存優(yōu)化策略其實都比較簡單,而且我們在開發(fā)中可能很少用到
因為我們常用的圖片框架比如Glide已經(jīng)將這些都封裝在里面了,所以一般情況下我們加載圖片時不需要做這些特殊操作。
關(guān)于Glide對于加載圖片都做了哪些優(yōu)化,有興趣的同學(xué)可以參考:【帶著問題學(xué)】Glide做了哪些優(yōu)化?
https://juejin.cn/post/6970683481127043085
4.2 圖片兜底策略
針對因activity、fragment泄漏導(dǎo)致的圖片泄漏,我們可以在onDetachedFromWindow時機(jī)進(jìn)行了監(jiān)控和兜底,具體流程如下:
通過這種方式可以方便地解決因Activity導(dǎo)致的圖片泄漏問題。
4.3 線上大圖監(jiān)控方案
當(dāng)運營在線上配置了不合理大小的圖片時,如果我們及時發(fā)現(xiàn),也會帶來內(nèi)存問題。
如果圖片本身大小就不合理,我們在這個基礎(chǔ)上談圖片優(yōu)化也沒有什么意義,因此大圖監(jiān)控這也是個比較常見的需求。
下面介紹幾種大圖監(jiān)控的方案:
4.3.1 ArtHook 方案
該方案采用weishu大佬寫的epic庫實現(xiàn),通過對ART虛擬機(jī)的hook,hook ImageView的 setImageBitmap 等方法。
解析對比方法參數(shù)中的 bitmap 寬高和 ImageView 實例的寬高,也可以獲得bitmap的實際大小。
如果圖片寬高比ImageView寬高大,或者圖片大小超出了閾值,就可以把相關(guān)信息上報。
這種方案的優(yōu)點在于:
侵入性極低,一次初始化配置即可hook全局的目標(biāo)View控件。
可以獲取代碼調(diào)用堆棧,方便開發(fā)者快速定位。
而缺點則在于:
兼容性存在問題,使用了hook系統(tǒng)API ,不能用于線上。
4.3.2 BaseActivity 方案
大部分應(yīng)用工程在業(yè)務(wù)發(fā)展的過程中都會沉淀封裝自己的BaseActivity ,通過在BaseActivity onDestroy中動態(tài)地檢測各個View控件,從而獲知圖片加載情況。
class BaseActivity : Activity(){
fun onDestory(){
if(isOpenCheckBitmap){
checkBitmapFromView()
}
}
fun checkBitmapFromView(){
//1、遍歷activity中的各個View控件
//2、獲取View控件加載的Bitmap
//3、對比Bitmap寬高與View寬高
}
}
這種方案的優(yōu)點在于:
兼容性強(qiáng),無任何反射。
加入簡單,沒有什么復(fù)雜邏輯。
缺點在于:
侵入性太強(qiáng),需要修改BaseActivity。
BaseActivity.onDestory本身可能被重寫,并不安全。
4.3.3 ASM方案
該方案在編譯流程進(jìn)行插樁,通過匹配setImageBitmap、 setBackground等關(guān)鍵方法,插入Bitmap大小檢測邏輯。
這種方案優(yōu)點在于:
編譯時期插樁,對開發(fā)過程無侵入性。
缺點在于:
通過插樁的方式打點,可能會增加編譯期耗時。
ASM代碼維護(hù)成本較高,使用起來不是那么方便。
4.3.4 registerActivityLifecycleCallback方案
通過registerActivityLifecycleCallback監(jiān)聽Activity生命周期,在onStop時進(jìn)行Bitmap大小檢測的邏輯。
private fun registerActivityLifecycleCallback(application: Application) {
application.registerActivityLifecycleCallbacks(object :
Application.ActivityLifecycleCallbacks {
override fun onActivityStopped(activity: Activity) {
checkBitmapIsTooBig(childViews)
}
})
}
這種方案對原始代碼無侵入性,同時使用起來比較簡單,也沒有兼容性問題,應(yīng)該屬于比較良好的方案。
詳細(xì)實現(xiàn)可見:BitmapCanary 誕生。
https://juejin.cn/post/6956138531789996040#heading-14
5、怎么做OOM線上監(jiān)控?
上文我們介紹了,可以使用LeakCanary在線下監(jiān)測內(nèi)存泄漏,但是LeakCanary只能在線下使用,有以下問題:
線下場景能跑到的場景有限,很難把所有用戶場景窮盡。碰到線上問題難以定位。
檢測過程需要主動觸發(fā)GC,Dump內(nèi)存鏡像造成app凍結(jié),造成測試過程中體驗不好。
適用范圍有限,只能定位Activity&Fragment泄漏,無法定位大對象、頻繁分配等問題。
hprof文件過大,如果整體上傳的話需要耗費很多資源。
下面我們就介紹一下快手開源的線上OOM監(jiān)控框架KOOM。
5.1 線上OOM監(jiān)控框架KOOM介紹
上面我們介紹了LeakCanary不能用于線上監(jiān)控的原因,所以要實現(xiàn)線上監(jiān)控功能,就需要解決以下問題:
1、監(jiān)控
主動觸發(fā)GC,會造成卡頓
2、采集
Dump hprof,會造成app凍結(jié)
Hprof文件過大
3、解析
解析耗時過長
解析本身有OOM風(fēng)險
其核心流程為三部分:
監(jiān)控OOM,發(fā)生問題時觸發(fā)內(nèi)存鏡像的采集,以便進(jìn)一步分析問題。
采集內(nèi)存鏡像,學(xué)名堆轉(zhuǎn)儲,將內(nèi)存數(shù)據(jù)拷貝到文件中,以下簡稱dump hprof。
解析鏡像文件,對泄漏、超大對象等我們關(guān)注的對象進(jìn)行可達(dá)性分析,解析出其到GC root的引用鏈以解決問題。
5.2 KOOM解決GC卡頓
LeakCanary通過多次GC的方式來判斷對象是否被回收,所以會造成性能損耗。
koom通過無性能損耗的內(nèi)存閾值監(jiān)控來觸發(fā)鏡像采集,具體策略如下:
1、Java堆內(nèi)存/線程數(shù)/文件描述符數(shù)突破閾值觸發(fā)采集。
2、Java堆上漲速度突破閾值觸發(fā)采集。
3、發(fā)生OOM時如果策略1、2未命中 觸發(fā)采集。
4、泄漏判定延遲至解析時。
我們并不需要在運行時判定對象是否泄漏,以Activity為例,我們并不需要在運行時判定其是否泄漏,Activity有一個成員變量mDestroyed,在onDestory時會被置為true,只要解析時發(fā)現(xiàn)有可達(dá)且mDestroyed為true的Activity,即可判定為泄漏。
通過將泄漏判斷延遲至解析時,即可解決GC卡頓的問題。
5.3 KOOM解決Dump hprof凍結(jié)app
Dump hprof即采集內(nèi)存鏡像需要暫停虛擬機(jī),以確保在內(nèi)存數(shù)據(jù)拷貝到磁盤的過程中,引用關(guān)系不會發(fā)生變化,暫停時間通常長達(dá)10秒以上,對用戶來講是難以接受的,這也是LeakCanary官方不推薦線上使用的重要原因之一。
利用Copy-on-write機(jī)制,fork子進(jìn)程dump內(nèi)存鏡像,可以完美解決這一問題,fork成功以后,父進(jìn)程立刻恢復(fù)虛擬機(jī)運行,子進(jìn)程dump內(nèi)存鏡像期間不會受到父進(jìn)程數(shù)據(jù)變動的影響。
流程如下圖所示:
KOOM隨機(jī)采集線上真實用戶的內(nèi)存鏡像,普通dump和fork子進(jìn)程dump阻塞用戶使用的耗時如下:
可以看出,基本可以做到無感知的采集內(nèi)存鏡像。
5.4 KOOM解決hprof文件過大
Hprof文件通常比較大,分析OOM時遇到500M以上的hprof文件并不稀奇,文件的大小,與dump成功率、dump速度、上傳成功率負(fù)相關(guān),且大文件額外浪費用戶大量的磁盤空間和流量。
因此需要對hprof進(jìn)行裁剪,只保留分析OOM必須的數(shù)據(jù),另外,裁剪還有數(shù)據(jù)脫敏的好處,只上傳內(nèi)存中類與對象的組織結(jié)構(gòu),并不上傳真實的業(yè)務(wù)數(shù)據(jù)(諸如字符串、byte數(shù)組等含有具體數(shù)據(jù)的內(nèi)容),保護(hù)用戶隱私。
裁剪hprof文件涉及到對hprof文件格式的了解,這里就不綴述了。
5.5 KOOM解決hprof解析的耗時與OOM
解析hprof文件,對關(guān)鍵對象進(jìn)行可達(dá)性分析,得到引用鏈,是解決OOM最核心的一步,之前的監(jiān)控和dump都是為解析做鋪墊。
解析分兩種,一種是上傳hprof文件由server解析,另一種是在客戶端解析后上傳報告(通常只有幾KB)。
KOOM選擇了端上解析,這樣做有兩個好處:
節(jié)省用戶流量。
利用用戶閑時算力,降低server壓力,這樣也符合分布式計算理念。
這樣就可以把解析過程拆解成以下兩個問題:
1、哪些對象需要分析,全部分析性能開銷太大,很難在端上完成,并且問題沒有重點也不利于解決。
2、性能優(yōu)化,作為一個debug組件,要在不影響用戶體驗的情況下完成解析,對性能有非常高的要求。
5.5.1 關(guān)鍵對象判定
KOOM只解析關(guān)鍵的對象,關(guān)鍵對象分為兩類,一類是根據(jù)規(guī)則可以判斷出對象已經(jīng)泄露,且持有大量資源的,另外一類是對象shallow / retained size 超過閾值。
Activity/fragment泄露判定即為第一種:
對于強(qiáng)可達(dá)的activity對象,其mDestroyed值為true時(onDestroy時賦值),判定已經(jīng)泄露。
類似的,對于fragment,當(dāng)mCalled值為true且mFragmentManager為null時,判定已經(jīng)泄露。
Bitmap/window/array/sufacetexture判定為第二種。
檢查bitmap/texture的數(shù)量、寬高、window數(shù)量、array長度等等是否超過閾值,再結(jié)合hprof中的相關(guān)業(yè)務(wù)信息,比如屏幕大小,view大小等進(jìn)行判定。
5.5.2 性能優(yōu)化
KOOM在LeakCanary解析引擎shark的基礎(chǔ)上做了一些優(yōu)化,將解析時間在shark的基礎(chǔ)上優(yōu)化了2倍以上,內(nèi)存峰值控制在100M以內(nèi)。用一張圖總結(jié)解析的流程:
詳細(xì)流程就不在這里綴述了,詳情可見:KOOM解析性能優(yōu)化。
https://juejin.cn/post/6860014199973871624#heading-13
5.6 KOOM使用
KOOM目前已經(jīng)開源,開源地址:
https://github.com/KwaiAppTeam/KOOM
直接參照接入指南接入即可,當(dāng)發(fā)現(xiàn)內(nèi)存超過閾值或者發(fā)生OOM時,就會觸發(fā)采集內(nèi)存快照,對hprof文件進(jìn)行裁剪并分析后得到報告。
KOOM的報告是json格式,并且大小在KB級別,樣式如下所示:
大概包括以下信息:
一些可能泄漏的類信息。
泄漏原因,gcRoot,泄漏實例數(shù)量等。
泄漏對象的引用鏈,方便定位問題。
可見KOOM上傳的數(shù)據(jù)量并不太大,但相對準(zhǔn)確,非常便于我們分析線上數(shù)據(jù)。
5.7 小結(jié)
本章主要介紹了線上監(jiān)控OOM的開源框架KOOM。
其實線上監(jiān)控OOM的框架各大廠都有開發(fā),比如美團(tuán)的Probe,字節(jié)的Liko。
https://tech.meituan.com/2019/11/14/crash-oom-probe-practice.html
https://juejin.cn/post/6908517174667804680#heading-7
不過大部分都沒有正式開源,只是一些文章介紹原理,有興趣的同學(xué)也可以都了解下。
總結(jié)
對于優(yōu)化的大方向,我們應(yīng)該優(yōu)先去做見效快的地方,主要有以下幾個部分:
內(nèi)存泄漏。
內(nèi)存抖動。
Bitmap大圖監(jiān)控。
OOM線上監(jiān)控。
我們還介紹了內(nèi)存優(yōu)化的多種實用工具:
可以使用Profile,MAT在開發(fā)時定位內(nèi)存抖動內(nèi)存泄漏問題。
線下開發(fā)、回歸、Monkey、壓測等環(huán)節(jié)可以自動集成LeakCanary檢測內(nèi)存泄漏;
圖片加載是內(nèi)存優(yōu)化的重點,我們可以結(jié)合圖片兜底策略與線上大圖監(jiān)控,優(yōu)化圖片內(nèi)存問題。
線上OOM時通過KOOM監(jiān)測,內(nèi)存超出閾值時主動dump內(nèi)存快照,通過上傳分析結(jié)果精準(zhǔn)。分析OOM問題。
內(nèi)存優(yōu)化是個復(fù)雜的過程,我們在做內(nèi)存優(yōu)化的過程中,需要結(jié)合多種工具,線上線下結(jié)合,系統(tǒng)化地配合來定位與解決問題。
作者:RicardoMJiang
https://juejin.cn/post/6975876569990447134
責(zé)任編輯:haq
-
Android
+關(guān)注
關(guān)注
12文章
3946瀏覽量
128042 -
內(nèi)存
+關(guān)注
關(guān)注
8文章
3071瀏覽量
74402
原文標(biāo)題:吹爆系列:Android 內(nèi)存還可以這樣優(yōu)化!
文章出處:【微信號:LinuxHub,微信公眾號:Linux愛好者】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。
發(fā)布評論請先 登錄
相關(guān)推薦
hyper 內(nèi)存,Hyper內(nèi)存:如何監(jiān)控與優(yōu)化hyper-v虛擬機(jī)的內(nèi)存使用
![hyper <b class='flag-5'>內(nèi)存</b>,Hyper<b class='flag-5'>內(nèi)存</b>:如何監(jiān)控與<b class='flag-5'>優(yōu)化</b>hyper-v虛擬機(jī)的<b class='flag-5'>內(nèi)存</b>使用](https://file1.elecfans.com/web3/M00/06/FB/wKgZO2eRojaAedKRAAJ1cEnLmOg140.png)
調(diào)試TCP協(xié)議連接的常用工具
嵌入式學(xué)習(xí)-飛凌嵌入式ElfBoard ELF 1板卡-mfgtools燒錄流程介紹之燒寫所需鏡像
嵌入式學(xué)習(xí)-飛凌嵌入式ElfBoard ELF 1板卡-mfgtools燒錄流程之燒寫方法
飛凌嵌入式ElfBoard ELF 1板卡-mfgtools燒錄流程介紹之燒寫所需鏡像
飛凌嵌入式ElfBoard ELF 1板卡-mfgtools燒錄流程之燒寫方法
如何優(yōu)化RAM內(nèi)存使用
Kali Linux常用工具介紹
堆棧和內(nèi)存的基本知識
![堆棧和<b class='flag-5'>內(nèi)存</b>的基本知識](https://file1.elecfans.com/web2/M00/05/7C/wKgaombQES2AFnb1AAEisWjn2dk976.png)
優(yōu)化 FPGA HLS 設(shè)計
![](https://file1.elecfans.com/web2/M00/01/0D/wKgZomazMGaAUzDoAAgY5AleqcA071.png)
評論