目標(biāo)
通常最占內(nèi)存的就是圖片搭幻,內(nèi)存優(yōu)化最優(yōu)先從圖片入手,排查下大內(nèi)存的圖片有哪些,是哪里產(chǎn)生的祟滴,是不是合理
定位
Android Studio → Dump Java Heap → 轉(zhuǎn)換格式 → 用MAT打開
打開 Histogram 并按 Shallow Heap 排序。查看各類型對(duì)象占用內(nèi)存情況歌溉,byte[] 遙遙領(lǐng)先垄懂,繼續(xù)看是什么對(duì)象產(chǎn)生的
去掉弱引用,查看GC Roots引用鏈
再按 Shallow Heap 排序痛垛,看到有12個(gè)占用內(nèi)存一模一樣的 byte[]草慧,大小是1048592字節(jié)=1M
我們看第一個(gè) byte[] 是什么,其余的同理
這個(gè)圖可以看出這個(gè) byte[] 其實(shí) Bitmap 的成員變量 mBuffer
這個(gè) bitmap 對(duì)象的所有成員變量都列在左側(cè)的 Attributes
對(duì)我們有用的信息是:這個(gè) bitmap 是512x512
繼續(xù)看這個(gè) bitmap 是被誰(shuí)持有的(定位我們自己的類)
這個(gè) bitmap 當(dāng)前有5個(gè)引用鏈匙头,但未必全都是GCRoots可達(dá)的漫谷,我們?nèi)サ舨豢蛇_(dá)的
看到只有3條引用鏈了,全部展開看看
看到有2條引用鏈都是Fresco的蹂析,肯定是圖片緩存相關(guān)的舔示,暫不關(guān)心
第三條引用鏈信息:
RCDataChangeMonitor 成員變量 ArrayList mRCDataChangedListeners
ArrayList 成員變量 Object[] array,長(zhǎng)度為12(數(shù)組長(zhǎng)度12电抚,并不代表每個(gè) index 都一定有值惕稻,末尾的可能尚未賦值,下文出現(xiàn)的數(shù)組也是如此)
array 的第3個(gè)元素是 CardPageVideoManager
CardPageVideoManager 成員變量 SimpleV2ListViewVideoScroller mVideoScroller
SimpleV2ListViewVideoScroller 成員變量 PinnedSectionListView mScrollView
PinnedSectionListView 成員變量 View[] mChildren蝙叛,長(zhǎng)度為12(項(xiàng)目里 PinnedSectionListView extends ListView extends ViewGroup)
第4個(gè)是 LinearLayout (大概率所有元素都是LinearLayout)
LinearLayout 成員變量 View[] mChildren俺祠,長(zhǎng)度為12
第2個(gè)是 RelativeLayout
RelativeLayout 成員變量 mBaselineView 是 **QiyiDraweeView **
在項(xiàng)目里,上面出現(xiàn)的類都是基礎(chǔ)類(有太多類在使用它們)甥温,無(wú)法得知是哪個(gè)具體的類
我們想知道是哪個(gè)頁(yè)面锻煌,哪個(gè)控件,什么時(shí)候產(chǎn)生的這個(gè) Bitmap
第一種方法:斷點(diǎn)
- QiyiDraweeView 里 setController() 的時(shí)候有設(shè)置回調(diào)監(jiān)聽 setControllerListener(listener)姻蚓,那么我們就在回調(diào) onFinalImageSet() 里設(shè)置斷點(diǎn)宋梧,并設(shè)置斷點(diǎn)條件 imageInfo.getWidth()==512 && imageInfo.getHeight()==512,當(dāng) Debug 停在這里的時(shí)候狰挡,我們就能拿到對(duì)應(yīng)的圖片 url
- 復(fù)制這個(gè) url捂龄,在 setController() 的調(diào)用方法里設(shè)置斷點(diǎn),并設(shè)置斷點(diǎn)條件 uri.toString().equals(圖片url)
- 當(dāng) Debug 停在此處加叁,終于看到了具體的業(yè)務(wù)類 GameAndAppCardModel倦沧,之后就可以針對(duì)性地查看
GameAndAppCardModel 的布局信息以及代碼
可以在此處斷點(diǎn)查看這個(gè) QiyiDraweeView 的 width 和 height 是不是512x512,如果差距較大它匕,那肯定是不合理的
第二種方法:繼續(xù)從 MAT 中挖掘信息
觀察 QiyiDraweeView 的 Attributes
比較有用的信息:
屬于 MainActivity展融,id=2131559271,measuredHeight 和 measuredWidth 都是155(猜測(cè)此處圖片加載是不合理的豫柬,控件是155x155告希,而加載的 Bitmap 是512x512扑浸,浪費(fèi)內(nèi)存,當(dāng)然以控件最終的 width 和 height 為準(zhǔn))
id 的16進(jìn)制寫法是 7f0d0367燕偶,查看 app\build\intermediates\symbols\debug\R.txt
這里我們可以得知這個(gè) QiyiDraweeView 的 id 名稱是 poster喝噪,那么可以搜索下整個(gè)項(xiàng)目
android:id="@+id/poster"
結(jié)果數(shù)太多,還是無(wú)法定位
我們看下 PinnedSectionListView指么,它引用鏈下的第一個(gè) View 很有可能是列表的 convertView酝惧,這里的話也就是 LinearLayout,找找看有沒有有用的信息
看到在 getView() 里 setTag() 設(shè)置的 GameAndAppCardModel.ViewHolder
原因
不合理的原因也很簡(jiǎn)單伯诬,就是布局里 ImageView 沒有指定寬高(固定多少 dp)晚唇,所以在 Fresco setResizeOptions() 的時(shí)候,獲取不到該控件的寬高(項(xiàng)目中使用 Universal-Image-Loader 也一樣有這樣的問題)姑廉。解決方法缺亮,見下篇