android 内存优化-MAT的使用及实例分析

1.mat内存优化分析包下载地址:

https://download.csdn.net/download/u010672559/10548897

说明:此包里面包含有MAT64位压缩包,内存泄漏demo-MemoryTest,内存分析工具文件hprof,mat工具直接解压就可以使用,如果打开报错,可能是jdk版本不匹配,需要自己去下载64位jdk安装即可

2.以下以具体实例来讲解MAT的使用方法

2.1实例场景为 点击button然后new 10000个imageview,使内存增加,然后finish会发现内存不降,手动点击GC也不会降低

说明:以下为Androidstudio-monitors-memory查看内存的视图,点击手动GC可触发系统GC回收可回收的资源

手动GC

dump hprop文件

具体主要代码如下

for (int i = 0; i < 10000; i++) {
    ImageView imageView = new ImageView(this);
    list.add(imageView);
}

此时点击button2次会发现内存上升很快

说明:以上为AndroidStudio的Monitors-Memory查看内存的视图

Allocated app实际使用的内存
Free 为空闲内存
我理解Allocated+Free为系统给app分配的总内存,
实际主要是看Allocated内存使用情况,如果这个比较高,则需要优化,具体多高看实际项目要求定义了

然后通过点击dump hprop图标导出hprop文件,具体对应mat_test_imageview_0.hprof文件(上面的下载的工具包里面有),然后通过MAT-File-Open heap dump...打开此文件,点击finish会看到如下视图

然后此页往下翻,找到Histogram

点击Histogram后再视图的上方找到图标,然后点击展开,点击Group by package可看到如下视图

参数解释:

- Shallow Heap 
Shallow size就是对象本身占用内存的大小,不包含其引用的对象内存,实际分析中作用不大。在堆上,看起来是一堆原生的byte[], char[], int[],对象本身的内存都很小。所以我们可以看到以Shallow Heap进行排序的Histogram图中,排在第一位第二位的是byte,char 
- Retained Heap 
Retained size是该对象自己的shallow size,加上从该对象能直接或间接访问到对象的shallow size之和。换句话说,retained size是该对象被GC之后所能回收到内存的总和。RetainedHeap可以更精确的反映一个对象实际占用的大小(因为如果该对象释放,retained heap都可以被释放)。

以上视图是从大到小的顺序排列的各个类占用的内存情况,其中主要是看Shallow Heap的值,这个值比如11593712,单位是B,即android包下面的对象占用了11M左右的内存,然后右键选择Merge shortest Paths to GC Roots-exclude all phantom/weak/soft etc.references, 意思是查看排除虚引用/弱引用/软引用等的引用链 (这些引用最终都能够被GC干掉,所以排除)可看到如下视图

然后展开排第一的项

然后就帮你定位到是MainActivity中的imageview占用的内存最多,此时你就能定位内存占用最多的是哪个地方了。之后便是优化工作,即只要在onDestroy()时将list集合置空就行了,然后你此时可以通过Monitors-Memory查看内存使用情况,发现按了2次button之后内存还是增加,finish后也不变,但是按了GC之后内存就迅速降低了,这就是效果。此时你也可以去导出此时的hprof文件,发现明显由以前的14.5M变为3.2M了,此时也可以通过同样的操作,Histogram-按包查看,看排第一的内存占用对象,发现不再是Imageview了,而是其他的对象了。这就说明当你在activity销毁的时候把list置空后imageview也随之被置空了,此时之前new的20000个imageview全部为空了,此时处于可回收状态,当手动按了GC之后,系统便会将其回收,内存一下就降下来了。

关于GC操作的理解:
置空或者加了缓存回收机制,会将超过LRU的内存或者置空的对象处理为可回收状态,等待系统GC时,便会回收,将处理过的处于可回收状态的对象回收掉,我们知道系统GC不会主动触发,只有系统自己内部回收机制才会触发,实际现象有界面跳转或切换的时候可能会触发GC,原因是此操作会加载新的内容,app会向系统申请分配多一些的内存,然后系统检会在此时检测是否有可以回收的地方,此时就触发GC回收一部分可以回收的对象,实际现象也是界面跳转时通过Android studio的Monitors观看到Allocated会增加,之后如果有回收或手动触发GC时Allocated会减少,Free增加,即Allocated+Free为总的系统分配给app的总内存,GC后Allocated减少,Free增加

2.2其他实例:

项目中有个页面需要gridview显示很多图片信息,使用imageload加载数据--------内存使用太高
实际分析:
点击进入gridview页面,将数据加载完,然后finish,重复以上操作,观看内存变化情况,发现反复finish
没有继续增加,说明没有内存泄漏,但是一直不减少,说明需要内存优化

然后使用MAT分析占用内存最多的对象,最后定位到了Imageloader对象,然后再通过网上查imageload的内存缓存机制发现最好不要用

options = new DisplayImageOptions.Builder()
        .cacheInMemory(true)

而应该是

ImageLoaderConfiguration config = new ImageLoaderConfiguration.Builder(
        context).threadPriority(Thread.NORM_PRIORITY - 2)
        .denyCacheImageMultipleSizesInMemory()
        .memoryCache( new LruMemoryCache(2 * 1024 * 1024))//优化部分
        .memoryCacheSize(2 * 1024 * 1024)//优化部分
        .memoryCacheSizePercentage(13)//优化部分
        .discCacheFileNameGenerator(new Md5FileNameGenerator())
        .tasksProcessingOrder(QueueProcessingType.FIFO)
        .discCacheSize(100 * 1024 * 1024)
        .build();

即增加LRU内存缓存机制,并设置阈值,内存缓存超过一定值的时候会将通过LRU的规则将超过的内存处理掉,使其变为可回收状态,之后GC一触发内存就马上掉下去了

3.其他:通过以上的方法,也可以通过调简单的demo去验证网上的那些内存优化的方法,即找个单独的因素,如工作线程一直加载图片,然后销毁的时候不停止线程,然后返回打开,finish操作,查看内存使用情况,分析占用内存最高的对象,然后在销毁的时候去停止工作线程,再和之前的内存情况比较,GC之后会不会降低来验证问题

猜你喜欢

转载自blog.csdn.net/u010672559/article/details/81098534