Android 内存优化方式

1. Android 内存大小

//获取的是正常情况下 app 内存大小,我的小米 5s 是 256 M
activiyManager.getMemoryClass() 

//在Android manifest 中设置 android:largeHeap="true" 之后 app  内存大小
activiyManager.getLargeMemoryClass();//Unit : M

完整代码 :

private  void calculate(){

        StringBuilder stringBuilder = new StringBuilder();

        ActivityManager activiyManager = (ActivityManager)getSystemService(Context.ACTIVITY_SERVICE);

        int memClass = activiyManager.getMemoryClass();// Unit : M

        //Application : mainfest --> largeHeap --> not goog choice --> In most device, it has no difference. But in my MI 5S, it did work.

        int LargememClass = activiyManager.getLargeMemoryClass();//Unit : M
        stringBuilder.append("memClass : " + memClass + "\n");
        stringBuilder.append("LargememClass : " + LargememClass + "\n");

        info.setText(stringBuilder.toString());
        Log.d("mooc", stringBuilder.toString());
    }

在我的小米 5s 中, 数据 :

这里写图片描述

2. Android 内存管理方式

2.1 Android 系统内存分配和回收方式

Android 的底层是 Linux,开发应用的框架层是 Java,一个 App 通常就是一个进程对应一个虚拟机

体验一下:

  • 记下你 app 的包名,我的 : package com.lizi.nativeandroid;
  • deploy app to your device

  • windows 搜索栏 输入 cmd,找到 Command Prompt,, 选择 Run as administartor

这里写图片描述

//进入 Android底层 Linux 系统命令,adb 需要配置环境变量
adb shell
//ps 查看系统里面进程的命令
ps

在进程列表中根据包名找到自己 app 进程 :

这里写图片描述

它的 父进程 :

这里写图片描述

查看 app 进程相关信息

//dumpsys meminfo packagename
dumpsys meminfo com.lizi.nativeandroid

重新部署了下项目, id 变了,请忽略

这里写图片描述

操作系统把内存分配给进程之后, 进程在 app 中分配内存

  • Dalvik Heap
  • Native Heap
  • apk

GC 只有在 Heap 剩余空间不够时才发出垃圾回收, 如果内存不够,申请 GC 回收的时候 GC 里面有很多对象,很对变量,要知道 GC 的时候也会占用 处理器的时间的。这种极端情况下, GC 会影响你 app 的响应。

GC 触发时, 所有的线程都会被暂停

2.2App 内存限制机制

每个 App 非配的最大内存限制,随不同设备而不同

吃内存大户 : 图片

2.3 切换应用时后台 App 清理机制、

Android 系统通过 分时复用 使多个应用可以同时运行, 当你使用你的 app 时,点击 back or home , 并没有完全销毁,只是在后台的缓存中,下次运行的时候,直接从后台掉出来,所以速度非常快。

App 切换时的 LRU Cache

LRU 算法 : 最近使用的排在最前,最少使用的可能被清理掉

清理的时候 发出 onTrimMemory() 回掉方法,这并不只在清理时回掉, 系统内存有变化的时候会发出相应的 onTrimMemory() 给各个应用。

代码 :

    @Override
    public void onTrimMemory(int level) {
        super.onTrimMemory(level);
        Log.d("mooc", "level : " + level);
    }

2.4 监控内存的几种方法

2.4.1 代码监控

 Float totalMemory = Runtime.getRuntime().totalMemory()*1.0f /(1024*1024);
 Float freeMemory = Runtime.getRuntime().freeMemory()*1.0f /(1024*1024);
 Float maxMemory = Runtime.getRuntime().maxMemory()*1.0f /(1024*1024);

 stringBuilder.append("totalMemory : " + totalMemory + "\n");
 stringBuilder.append("freeMemory : " + freeMemory + "\n");
 stringBuilder.append("maxMemory : " + maxMemory + "\n");

这里写图片描述

25M 是系统分配的内存, 最大上限是 512M

2.4.2 Android Monitor | Android Profiler

2.4.3 Android Device Monitor

这里写图片描述

点击你的 app, 点击 Cause GC , 内存大小变化就会出来

这里写图片描述

3. App 内存优化方法

  • 数据结构优化
  • 对象复用
  • 避免内存泄漏

3.1 数据结构优化

3.1.1 频繁字符串拼接使用 StringBuilder

Talking is cheap, show me the code.


...... 

private int rowLength = 20;
private int length = 300;
private int [][] intMatrix = new int[rowLength][length];
private Random ran = new Random();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        findView();

        calculate();

        for (int i = 0; i < rowLength; i++) {
            for (int j = 0; j < length; j++) {
                intMatrix[i][j] = ran.nextInt();
            }
        }
    }

 findViewById(R.id.starjoin).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Log.d("mooc", "starjoin clicked !");
                doJoin();
            }
        });

        findViewById(R.id.starbld).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Log.d("mooc", "starbld clicked !");
                doBld();
            }
        });

 private void doBld() {
        StringBuilder rowStr = new StringBuilder();
        Log.d("mooc", "doBld start : ");
        for (int i = 0; i < rowLength; i++) {
            for (int j = 0; j < length; j++) {
                rowStr.append(intMatrix[i][j]);
                rowStr.append(",");
            }
            Log.d("mooc", "doBld rowStr : " + i);
        }
        Log.d("mooc", "doBld rowStr : " + rowStr.toString().length());
    }

    private void doJoin() {
        String rowStr = "";
        Log.d("mooc", "doJoin start : ");
        for (int i = 0; i < rowLength; i++) {
            for (int j = 0; j < length; j++) {
                rowStr = rowStr + intMatrix[i][j];
                rowStr = rowStr + ",";
            }
            Log.d("mooc", "doJoin rowStr : " + i);
        }
        Log.d("mooc", "doJoin rowStr : " + rowStr.length());
    }

当调用 doJoin(),性能 3S:

12-03 20:22:08.322 10917-10917/com.lizi.nativeandroid D/mooc: starjoin clicked !
12-03 20:22:08.322 10917-10917/com.lizi.nativeandroid D/mooc: doJoin start : 
12-03 20:22:08.334 10917-10917/com.lizi.nativeandroid D/mooc: doJoin rowStr : 0
12-03 20:22:08.355 10917-10917/com.lizi.nativeandroid D/mooc: doJoin rowStr : 1
12-03 20:22:08.406 10917-10917/com.lizi.nativeandroid D/mooc: doJoin rowStr : 2
12-03 20:22:08.465 10917-10917/com.lizi.nativeandroid D/mooc: doJoin rowStr : 3
12-03 20:22:08.542 10917-10917/com.lizi.nativeandroid D/mooc: doJoin rowStr : 4
12-03 20:22:08.680 10917-10917/com.lizi.nativeandroid D/mooc: doJoin rowStr : 5
12-03 20:22:08.794 10917-10917/com.lizi.nativeandroid D/mooc: doJoin rowStr : 6
12-03 20:22:08.926 10917-10917/com.lizi.nativeandroid D/mooc: doJoin rowStr : 7
12-03 20:22:09.060 10917-10917/com.lizi.nativeandroid D/mooc: doJoin rowStr : 8
12-03 20:22:09.222 10917-10917/com.lizi.nativeandroid D/mooc: doJoin rowStr : 9
12-03 20:22:09.427 10917-10917/com.lizi.nativeandroid D/mooc: doJoin rowStr : 10
12-03 20:22:09.609 10917-10917/com.lizi.nativeandroid D/mooc: doJoin rowStr : 11
12-03 20:22:09.791 10917-10917/com.lizi.nativeandroid D/mooc: doJoin rowStr : 12
12-03 20:22:10.035 10917-10917/com.lizi.nativeandroid D/mooc: doJoin rowStr : 13
12-03 20:22:10.285 10917-10917/com.lizi.nativeandroid D/mooc: doJoin rowStr : 14
12-03 20:22:10.514 10917-10917/com.lizi.nativeandroid D/mooc: doJoin rowStr : 15
12-03 20:22:10.781 10917-10917/com.lizi.nativeandroid D/mooc: doJoin rowStr : 16
12-03 20:22:11.089 10917-10917/com.lizi.nativeandroid D/mooc: doJoin rowStr : 17
12-03 20:22:11.410 10917-10917/com.lizi.nativeandroid D/mooc: doJoin rowStr : 18
12-03 20:22:11.801 10917-10917/com.lizi.nativeandroid D/mooc: doJoin rowStr : 19
12-03 20:22:11.801 10917-10917/com.lizi.nativeandroid D/mooc: doJoin rowStr : 65928
12-03 20:22:11.802 10917-10917/com.lizi.nativeandroid I/Choreographer: Skipped 208 frames!  The application may be doing too much work on its main thread.
12-03 20:22:26.867 10917-10917/com.lizi.nativeandroid D/mooc: level : 20

当调用 doBld(),性能 2 ms:

12-03 20:28:40.110 10917-10917/com.lizi.nativeandroid D/mooc: starbld clicked !
12-03 20:28:40.111 10917-10917/com.lizi.nativeandroid D/mooc: doBld start : 
12-03 20:28:40.111 10917-10917/com.lizi.nativeandroid D/mooc: doBld rowStr : 0
12-03 20:28:40.111 10917-10917/com.lizi.nativeandroid D/mooc: doBld rowStr : 1
12-03 20:28:40.111 10917-10917/com.lizi.nativeandroid D/mooc: doBld rowStr : 2
12-03 20:28:40.111 10917-10917/com.lizi.nativeandroid D/mooc: doBld rowStr : 3
12-03 20:28:40.111 10917-10917/com.lizi.nativeandroid D/mooc: doBld rowStr : 4
12-03 20:28:40.111 10917-10917/com.lizi.nativeandroid D/mooc: doBld rowStr : 5
12-03 20:28:40.111 10917-10917/com.lizi.nativeandroid D/mooc: doBld rowStr : 6
12-03 20:28:40.111 10917-10917/com.lizi.nativeandroid D/mooc: doBld rowStr : 7
12-03 20:28:40.111 10917-10917/com.lizi.nativeandroid D/mooc: doBld rowStr : 8
12-03 20:28:40.112 10917-10917/com.lizi.nativeandroid D/mooc: doBld rowStr : 9
12-03 20:28:40.112 10917-10917/com.lizi.nativeandroid D/mooc: doBld rowStr : 10
12-03 20:28:40.112 10917-10917/com.lizi.nativeandroid D/mooc: doBld rowStr : 11
12-03 20:28:40.112 10917-10917/com.lizi.nativeandroid D/mooc: doBld rowStr : 12
12-03 20:28:40.112 10917-10917/com.lizi.nativeandroid D/mooc: doBld rowStr : 13
12-03 20:28:40.112 10917-10917/com.lizi.nativeandroid D/mooc: doBld rowStr : 14
12-03 20:28:40.112 10917-10917/com.lizi.nativeandroid D/mooc: doBld rowStr : 15
12-03 20:28:40.112 10917-10917/com.lizi.nativeandroid D/mooc: doBld rowStr : 16
12-03 20:28:40.112 10917-10917/com.lizi.nativeandroid D/mooc: doBld rowStr : 17
12-03 20:28:40.112 10917-10917/com.lizi.nativeandroid D/mooc: doBld rowStr : 18
12-03 20:28:40.112 10917-10917/com.lizi.nativeandroid D/mooc: doBld rowStr : 19
12-03 20:28:40.112 10917-10917/com.lizi.nativeandroid D/mooc: doBld rowStr : 65928

3.1.2 ArrayMap 、SparseArray 替换 HashMap

  • 内存使用更少
  • 数据比较多的时候效率比较高
  • 使用起来和 HashMap 用法一致

3.1.3 内存抖动

代码 :

    private int rowLength2 = 10;
    private int length2 = 420000;
    private void doChurn(){
        Log.d("mooc", "doChurn start : ");
        for (int i = 0; i < rowLength2; i++) {
            //重点,变量放在这里,每次重新一行赋值的时候,这里又有新的变量,上一行的变量就废弃,GC
            //优化,变量放在脑袋上的循环外面重复使用就可以了
            String[] strMatrix = new String[length2];
            for (int j = 0; j < length2; j++) {
                //内存抖动原因:大量字符串占用空间 --> 420000
                strMatrix[j] = String.valueOf(ran.nextDouble());
            }
            Log.d("mooc", "doChurn strMatrix : " + i);
        }
        Log.d("mooc", "doChurn strMatrix end : " );
    }

这里写图片描述

3.1.4 再小的 Class 耗费 0.5 kb

3.1.5 HashMap 一个 entry 需要额外占用 32B

3.2 对象复用

  • 复用系统自带的资源
  • ListView/GridView 的 ConvertView 复用
  • 避免在 onDraw 方法中执行对象的创建

3.3 避免内存泄漏

由于代码瑕疵,导致这块内存,虽然停止不用了,但是依然被其它东西引用这,使得 GC 没法对它回收

内存泄漏会导致剩余可用 Heap 越来越少,频繁触发 GC

4. OOM 问题优化

4.1 OOM 问题分析

Android 内存有限,展示图片容易OOM –> =-= | o.o | T_T

4.2 强引用、软引用的意义

private String strongRef;
private SoftReference<String> softRef;

strongRef = String.valueOf(Math.random());
softRef = new SoftReference<String>(String.valueOf(Math.random()));

场景 :

变量定义在 Activity 中,生命周期和 Activity 同步,Activity 存活期间这个变量所保存的内存空间不会被释放


强引用 : 在它的生命周期里它的内存空间不会被回收

软引用 : 在它的生命周期里它的内存空间 只要是内存不够, GC 可以把它回收掉

4.3 优化 OOM 问题的方法

  • 注意临时 BItmap 对象的及时回收 -> 置空| .recyle()
  • 注意 BItmap 的浪费
  • Try catch 某些大内存非配的操作
  • 加载 Bitmap :缩放比例、解码格式、局部加载 (解决绝大部分)

参考链接 : https://www.imooc.com/video/13672

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值