Android内存优化

一、Android系统的内存分配和回收方式

  • 一个App通常就是一个进程,对应一个虚拟机
  • GC只有在Heap剩余空间不够时,才触发垃圾回收
  • GC触发时,所有线程都会被暂停

二、APP的内存限制

  • 每个APP分配的最大内存限制,随着设备不同而不同
  • 吃内存大户:图片

三、切换应用时后台APP清理机制

  1. App之间切换时,内存管理使用LRU算法(最近使用的排在最前面,最少可能被清理掉)
  2. onTrimMemory方法:当系统内存变化时,会调用该回掉方法。该方法会得到当前内存级别,我们可以根据级别来提前管理内存(例如当内存不够时,清理app的内存,可以降低被系统清理的可能)

四、内存监控的几种方法

  1. AS代码输出内存信息
        stringBuilder.append("memClass: " + memClass + "\n");
        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("maxMemory: " + maxMemory + "\n");
        stringBuilder.append("totalMemory: " + totalMemory + "\n");
        stringBuilder.append("freeMemory: " + freeMemory + "\n");
        Log.d("newApp", stringBuilder.toString());
  1. Android Studio再带的监控:Android Monitor(它可以监控内存(分配的总内存和空闲内存)、CPU和网络的情况)

3.更详细的检测工具:Android Device Monitor。
它可以监控推内存的变化(只需点击Gause GC触发垃圾回收器,就可以查看当前heap内存情况)

五、内存优化方法

  1. 数据结构
  • 拼接大量字符串时用StringBuilder
  • ArrayMap、SparseArray替换HashMap
  • 内存抖动:
    • 原因:反复申请大量内存,每次申请完很快就弃之不用;这时候若heap内存不够,GC就会对弃之不用的内存进行回收,内存再次变小;频繁的出现内存不断变化就是内存抖动
    • 解决方案:将重复使用的变量放在外面(即更大的变量作用域或全局作用域中)
  • 再小的class耗费0.5KB
  1. 对象的复用
  • 复用系统资源
  • ListView/GridView/RecyclerView的ContentView的复用
  • 避免再onDraw方法里面进行对象的创建
  1. 避免内存泄漏

  2. 内存泄漏是什么?
    申请一块内存(如创建对象),不再使用时GC会回收;但由于代码问题,依然被其它东西引用着,导致无法回收

  3. 严重后果?
    内存泄漏会导致剩余的可用heap越来越少,并且频繁的触发GC

  4. 举一个内存泄漏的例子,说一下内存泄漏原因和解决方法

-  例子:点击按钮开启一个永不停止的线程(该线程类是Activity的内部类),退出Activity,反复这个过程
-  原因:Activity的内部类会隐含的引用当前Activity,若Activity退出时,线程仍然运行,则Activity由于被这个线程引用而无法被GC回收
-  解决方法:
    1.  线程创建在Service中,让service来管理,service由于长期后台运行,不会发生service关闭而线程仍然运行的情况。
    2.  使用软引用或者弱引用来处理Activity内部类中对当前Activity的引用
  1. 内存泄漏主要是Activity泄漏
  2. 用Application的Context而不是Activity Context(如网络请求回掉方法中的土司框的Context用Application的Context)
  3. 数据库操作发生内存泄漏:Cursor对象是否及时关闭

六、OOM问题的优化

1.分析:
- OOM是内存溢出(Out Of Memory的缩写)
- OOM的必然性:每个App运行有一个内存上限
- OOM主要是图片

  1. 强引用、软引用、弱引用
    • 强引用在变量的生命周期中不会被回收
    • 软引用在变量的生命周期中只要内存不够就会被回收
    • 弱引用在变量的生命周期中只要触发GC就可能被回收
  2. 解决OOM问题的方法:
    1. 临时Bitmap对象的及时回收(recycle)
    2. 避免Bitmap浪费
    3. try catch大内存分配操作的代码块(不推荐,不能解决根本问题:内存分配失败时,此方法只能防止程序崩溃,不能让程序顺畅运行)
    4. 最优方法,在加载Bitmap时,使用
      • 缩放:设置Options调整缩放比例
      • 解码格式:将默认的ARGB_8888换成RGB_565来显示图片
      • 局部加载:使用BitmapRegionDecoder
      • 软引用:
      • LRU算法:

推荐阅读更多精彩内容