记一次内存溢出分析

1,789 阅读2分钟

问题背景

媒体应用播放音乐一晚上偶现程序崩溃

开始分析

dropbox log

java.lang.OutOfMemoryError: Failed to allocate a 72 byte allocation with 8 free bytes and 8B until OOM, target footprint 402653184, growth limit 402653184
	at com.google.android.exoplayer2.ExoPlayerImplInternal.handleMessage(ExoPlayerImplInternal.java:563)
	at android.os.Handler.dispatchMessage(Handler.java:106)
	at android.os.Looper.loop(Looper.java:219)
	at android.os.HandlerThread.run(HandlerThread.java:67)

找到对应时间的log 发现此时heap大小超出了分配大小 并且此前已经多次Starting a blocking GC Alloc 均无法降低占用 并且报OutOfMemoryError 确认为内存溢出

查看系统当前分配heap大小

adb shell getprop | grep heap

内存溢出处log日志


07-08 04:12:05.811  4384  5221 I : Clamp target GC heap from 407MB to 384MB  
07-08 04:12:05.811  4384  5221 I : Alloc concurrent copying GC freed 0(0B) AllocSpace objects, 0(0B) LOS objects, 0% free, 383MB/384MB, paused 39us total 943.805ms
07-08 04:12:05.811  4384  5102 I  WaitForGcToComplete blocked Alloc on HeapTrim for 2.844s
07-08 04:12:05.811  4384  5102 I : Starting a blocking GC Alloc
07-08 04:12:05.811  4384  4408 I : Waiting for a blocking GC Alloc
07-08 04:12:05.811  4384  4384 I : Waiting for a blocking GC Alloc
07-08 04:12:05.811  4384  5221 W : Throwing OutOfMemoryError "Failed to allocate a 192 byte allocation with 72 free bytes and 72B until OOM, target footprint 402653184, growth limit 402653184" (VmSize 7736116 kB)
07-08 04:12:05.811  4384  4486 I : Waiting for a blocking GC Alloc
07-08 04:12:05.811  4384  5221 I : Waiting for a blocking GC Alloc

首先记录刚刚开始播放歌曲时内存快照文件 使如下命令

adb shell am dumpheap com.xxx.xxx  /data/local/tmp/xxxx.hprof

取出hprof文件并拖入Androidstudio 打开可以看到retained 240M

image.png

然后播放歌曲3个小时候再取出内存快照查看

19cbbe95994248a2aa4dbfc6c47c887f.png 首先查看fragment和music

f3a41f5755fe4b6a8aa22134bbc91284.png 一通分析发现几个100M以上的都是因为引用了一个 ArrayList -> nowPlayingList 这里就基本定位问题了
继续看此list为何这么大 找到nowPlayingList变化的地方

private fun updateList(list: List<Music>?){
    if(!list.isNullOrEmpty()){
        nowPlayingList.addAll(list)
    }
}

此处为歌曲每播放一首就会更新一下此列表但是此处list返回的是整个播放历史列表,每播放一首歌曲就会导致此列表追加之前所有的播放列表

因此更新数据先clear即可

private fun updateList(list: List<Music>?){
    if(!list.isNullOrEmpty()){
        nowPlayingList.clear()
        nowPlayingList.addAll(list)
    }
}

来吧,run!!再来3个小时音乐!!

再次播放歌曲3小时后内存快照

image.png

可以看到基本上已经没有问题了

收工!!!!!