晓我课堂

Android内存优化

2021-04-28  本文已影响0人  海_3efc

Android UI优化
Android性能优化 - CPU/GPU篇
Android内存优化

一、为什么要进行内存优化

在实际开发中,对对象的引用使用不当导致无法被GC,造成内存泄漏,甚至内存溢出(OOM),程序变慢,程序崩溃。
站在用户角度就是应用卡,不流畅,对应用慢慢失去兴趣。最终APP慢慢走向下线。

二、介绍Android系统内存管理机制

2.1 针对进程的内存策略
2.2 针对对象、变量的内存策略
内存交互与操作过程图

MESI缓存一致性协议
多个cpu从主内存读取同一个数据到各自的高速缓存,当其中某个cpu修改了缓存中的数据,该数据就会马上同步回主内存,其他cpu通过总线嗅探机制可以感知到数据变化从而将自己缓存中的数据失效。

三、Android GC机制简介

1.对象存活判断

Android中哪些对象可作为GC Roots呢?
1.虚拟机栈(栈帧中的本地变量表)中引用的对象;
2.方法区中类静态属性引用的对象;
3.方法区中类静态属性引用的对象;
4.本地方法栈中JNI(即一般说的Native方法)引用的对象

2.垃圾回收算法
3.Java 堆GC角度划分

在Android中,通过new的对象都会分配到堆内存中,堆内存有分为两大块:永久空间和堆空间。

年轻代

年轻代中分配比例大约为:Eden占8/10,from和to各占1/10。
内存分配及GC流程如下:
1.新创建的对象都会分配到Eden区;
2.当触发GC时会回收掉Eden区的对象,幸存的对象会被复制到From区,新创建的对象继续放到Eden区。
3.再次触发GC时会回收掉Eden区和From区的对象,再有幸存对象时,则全部复制到to区,继续步骤1,新建对象;
4.等到Eden区分配满,再次触发GC时,会回收掉Eden区和to区的对象,最后把幸存的对象全部复制到from区,然后继续执行步骤1;
5.如此循环往复,每次GC都会把Eden区和from或者to中的对象进行回收,并全部复制到from或to中空的那个中,每次有幸存者时计数增加1,当幸存者的技术累计到一定数量时,仍未被回收,则该对象被则被复制到老年代区;

针对年轻代的垃圾回收即Young GC。

老年代

在年轻代中经历了Ñ次(可配置)垃圾回收后仍然存活的对象,就会被复制到年老代中。因此,可以认为年老代中存放的都是一些生命周期较长的对象。

针对年老代的垃圾回收即Full GC。

在完全GC后,若Survivor区及年老代仍然无法存放从Eden复制过来的对象,则会导致JVM无法在Eden区为新生成的对象申请内存,即出现“内存不足”。

OOM

OOM(“Out of Memory”)异常一般主要有如下2种原因:

1.年老代溢出,表现为:java.lang.OutOfMemoryError:Javaheapspace
这是最常见的情况,产生的原因可能是:内存泄漏、内存碎片等原因。
这种方式的OOM是我们本文的重点。

2.持久代溢出,表现为:java.lang.OutOfMemoryError:PermGenspace

四、常用辅助监测工具

1.Android Monitor中DDMS下的Heap Dump

Android Device Monitor工具在Android SDK目录下的tools中,点击直接运行,即可。

image.png

其中总览视图可以查看整体的内存情况,表中的显示信息如下所示:

Heap Dump检测内存泄漏:通常做法是使用Update Heap进行内存监听,然后操作可能发生泄漏的APP功能、界面,并点击Cause GC进行手动GC,经过多次操作后查看data object的Total Size大小是否有很大的变化,如果有则可能发生了内存泄漏,导致内存使用不断增大。

2.Android Monitor中DDMS下的Allocation Tracker

使用Heap Dump可以让你对APP的内存整体使用情况进行掌控,但缺点是无法了解每块内存具体分配给哪个对象了,这时就需要使用Allocation Tracker工具来进行内存跟踪。它允许你在执行某些操作的同时监视在何处分配对象,了解这些分配使你能够调整与这些操作相关的方法调用,以优化应用程序性能和内存使用。

Allocation Tracker能够做到如下的事情:

3.MAT

想要深入的进行分析并确定内存泄漏,就要分析疑似发生内存泄漏时所生成堆存储文件。堆存储文件可以使用DDMS或者Memory Monitor来生成,输出的文件格式为hprof,然后使用MAT来分析堆存储文件。

MAT,全称为Memory Analysis Tool,是对内存进行详细分析的工具,它是Eclipse的插件,如果用Android Studio进行开发则需要单独下载它,可独立运行。下载地址

4.LeakCanary库

LeakCanary库是github上优秀的第三方开源库,通过该库可以监控内存是否有泄漏。其原理是利用对象引用可达性分析算法来进行检测的,当出现内存泄漏时会在通知栏中进行通知。
使用方式不过多介绍,请参考LeakCanary库

5.Android studio自带的Profiler工具

启动Andrroid studio,连接手机或模拟器,点击下按钮,启动要监控的应用

等应用启动后,在as底部会启动profiler分析器,点击Memory行会进入到Memory使用详情界面。

等采集完数据后,AS会自动分析Heap Dump的数据,如下图

图中筛选项说明

我们筛选时一般按app heap进行筛选,只需要看我们自己的app堆内存分配情况。

各列信息说明

针对1、2、3工具使用可参考:Android 内存检测工具

五、常见内存问题及优化方案

1.内存泄漏

文章开头也说明了内存gc机制,所谓内存泄漏(Memory Leak)是指程序中己动态分配的堆内存由于某种原因程序未释放或无法释放,gc时一直不能被回收,造成系统内存的浪费,导致程序运行速度减慢甚至系统崩溃等严重后果。

2.内存抖动

App在使用过程中内存数据高低波动明显,或者界面停止不动(无任何操作)内存在不断增加、降低、再增加、再降低如此循环。
同样,举个例子简单辅助说明下:

public void click(View view) {
        int id = view.getId();
        if(id == R.id.btn_more_fragments){
            //startActivity(new Intent(this,RadarChartActivity.class));
            handler.sendEmptyMessageDelayed(100,1000);
        }
    }

    private Handler handler = new Handler(){
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            for (int i = 0;i< 100;i++){
                byte[] b = new byte[2048];
            }
            handler.sendEmptyMessageDelayed(100,100);
        }
    };

运行后观察内存,如下图

优化方法采用内存复用方式将byte[] b放到循环外面作为Activity的成员变量中,优化代码如下:

//放到全局
private byte[] b;
...
 for (int i = 0;i< 100;i++){
         b = new byte[2048];
 }

对操作大数据时,如Bitmap尽量做到内存复用,而不是频繁的new对象去分配内存空间。

3.内存碎片

内存碎片指在堆内存中存在小块的内存空间,始终得不到利用,从而造成内存空间浪费。

4KB来为内存分页中每一页的大小。

通过使用Android support V4中提供的Pools对象池,可以很好的解决内存碎片问题。

上一篇下一篇

猜你喜欢

热点阅读