內(nèi)存優(yōu)化:圖片定位

目標(biāo)

通常最占內(nèi)存的就是圖片,內(nèi)存優(yōu)化最優(yōu)先從圖片入手,排查下大內(nèi)存的圖片有哪些,是哪里產(chǎn)生的,是不是合理

定位

Android Studio → Dump Java Heap → 轉(zhuǎn)換格式 → 用MAT打開(kāi)

打開(kāi) Histogram 并按 Shallow Heap 排序。查看各類(lèi)型對(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í)持有的(定位我們自己的類(lèi))
這個(gè) bitmap 當(dāng)前有5個(gè)引用鏈,但未必全都是GCRoots可達(dá)的,我們?nèi)サ舨豢蛇_(dá)的

看到只有3條引用鏈了,全部展開(kāi)看看

看到有2條引用鏈都是Fresco的,肯定是圖片緩存相關(guān)的,暫不關(guān)心

第三條引用鏈信息:

  1. RCDataChangeMonitor 成員變量 ArrayList mRCDataChangedListeners

  2. ArrayList 成員變量 Object[] array,長(zhǎng)度為12(數(shù)組長(zhǎng)度12,并不代表每個(gè) index 都一定有值,末尾的可能尚未賦值,下文出現(xiàn)的數(shù)組也是如此)

  3. array 的第3個(gè)元素是 CardPageVideoManager

  4. CardPageVideoManager 成員變量 SimpleV2ListViewVideoScroller mVideoScroller

  5. SimpleV2ListViewVideoScroller 成員變量 PinnedSectionListView mScrollView

  6. PinnedSectionListView 成員變量 View[] mChildren,長(zhǎng)度為12(項(xiàng)目里 PinnedSectionListView extends ListView extends ViewGroup)

  1. 第4個(gè)是 LinearLayout (大概率所有元素都是LinearLayout)

  2. LinearLayout 成員變量 View[] mChildren,長(zhǎng)度為12

  3. 第2個(gè)是 RelativeLayout

  4. RelativeLayout 成員變量 mBaselineView 是 **QiyiDraweeView **

在項(xiàng)目里,上面出現(xiàn)的類(lèi)都是基礎(chǔ)類(lèi)(有太多類(lèi)在使用它們),無(wú)法得知是哪個(gè)具體的類(lèi)

我們想知道是哪個(gè)頁(yè)面,哪個(gè)控件,什么時(shí)候產(chǎn)生的這個(gè) Bitmap

第一種方法:斷點(diǎn)

  1. QiyiDraweeView 里 setController() 的時(shí)候有設(shè)置回調(diào)監(jiān)聽(tīng) 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
1)
  1. 復(fù)制這個(gè) url,在 setController() 的調(diào)用方法里設(shè)置斷點(diǎn),并設(shè)置斷點(diǎn)條件 uri.toString().equals(圖片url)
2)
  1. 當(dāng) Debug 停在此處,終于看到了具體的業(yè)務(wù)類(lèi) GameAndAppCardModel,之后就可以針對(duì)性地查看
    GameAndAppCardModel 的布局信息以及代碼

可以在此處斷點(diǎn)查看這個(gè) QiyiDraweeView 的 width 和 height 是不是512x512,如果差距較大,那肯定是不合理的

3)

第二種方法:繼續(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)制寫(xiě)法是 7f0d0367,查看 app\build\intermediates\symbols\debug\R.txt

這里我們可以得知這個(gè) QiyiDraweeView 的 id 名稱(chēng)是 poster,那么可以搜索下整個(gè)項(xiàng)目

android:id="@+id/poster"

結(jié)果數(shù)太多,還是無(wú)法定位

我們看下 PinnedSectionListView,它引用鏈下的第一個(gè) View 很有可能是列表的 convertView,這里的話(huà)也就是 LinearLayout,找找看有沒(méi)有有用的信息

看到在 getView() 里 setTag() 設(shè)置的 GameAndAppCardModel.ViewHolder

原因

不合理的原因也很簡(jiǎn)單,就是布局里 ImageView 沒(méi)有指定寬高(固定多少 dp),所以在 Fresco setResizeOptions() 的時(shí)候,獲取不到該控件的寬高(項(xiàng)目中使用 Universal-Image-Loader 也一樣有這樣的問(wèn)題)。解決方法,見(jiàn)下篇

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容