android 内存 1

155 阅读5分钟

1 描述

  • 基于Linux内存管理
  • Android有垃圾自动回收机制不需要手动干预,(GC机制)但也因此,出现内存问题,如内存泄漏与溢出问题
  • App唯一释放内存的方法就是释放App持有的对象引用,使GC可以回收。
  • Android应用的进程都是从一个叫做Zygote的进程fork出来的。
  • Android系统为每一个应用程序都设置了一个硬性的Dalvik Heap Size最大限制阈值(14M,24M,48),视机型定   其内存使用是有上限的
  • 通过命令行adb shell dumpsys meminfo -a packagename查看内存详细占用情况:

2 内存分配:

方法区:方法区存放的是类信息、常量、静态变量,所有线程共享区域。

虚拟机栈:每个方法在执行的同时都会创建一个栈帧(Stack Frame)用于存储局部变量表、操作数栈、动态链接、
方法出口等信息,线程私有区域。

本地方法栈:与虚拟机栈类似,区别是虚拟机栈为虚拟机执行Java方法服务,本地方法栈为虚拟机使用到的Native
方法服务。

堆:JVM管理的内存中最大的一块,所有线程共享;用来存放对象实例,几乎所有的对象实例都在堆上分配内存;
此区域也是垃圾回收器(Garbage Collection)主要的作用区域,内存泄漏就发生在这个区域。

程序计数器:可看做是当前线程所执行的字节码的行号指示器;如果线程在执行Java方法,这个计数器记录的是正在
执行的虚拟机字节码指令地址;如果执行的是Native方法,这个计数器的值为空(Undefined)。
---------------------------------------------------------------------------------
分配size:Android系统为每一个应用程序都设置了一个硬性的Dalvik Heap Size最大限制阈值(14M,24M,48)
,视机型定,达到阈值则会引发泄漏OutOfMemoryError

查看:ActivityManager.getMemoryClass()可以用来查询当前应用的Heap Size阈值;
      通过命令行adb shell dumpsys meminfo -a packagename查看内存详细占用情况
  • 有一种习惯说法:把Java的内存区域分为堆内存(Heap)和栈内存(Stack),Stack访问快,Heap访问慢,Stack中保存的是对象的引用(指针),Heap中保存的是对象的实例。
  • Android系统有六类进程:前台进程、可见进程、次要服务、后台进程、内容供应节点、空进程。有内存管理需求的人可以用MinFreeManager之类的软件进行进程管理,分别为六类进程设定不同的阈值来操纵系统的内存分配机制。

3 内存回收

额 这个扯到算法了 这里记一下:

  1. 最基础的收集算法:分为“标记”和“清除”两个阶段

这种方法有两个不足点:

  • 效率问题,标记和清除两个过程的效率都不高;
  • 空间问题,标记清除之后会产生大量的不连续的内存碎片。

  2. 标记-整理算法

先标记需要回收的对象(标记过程与“标记-清除”算法一样),然后把所有存活的对象都向一端移动,然后直接清理掉端边界以外的内存。

  • 避免了内存碎片;
  • 避免了“复制”算法50%的空间浪费;
  • 主要针对对象存活率高的老年代。

4 发生OOM情况

  1. 对象泄漏(内存泄漏) 如短的生命周期被长的生命周期给引用,导致释放不了,如内部类引用外部类(如Handler,Thread)、Context泄露 被单例引用等
  2. 内存溢出 ,申请的内存超出heap size 所分配的值
  3. 常见的数据库查询Cursor, 文件读写流等, 用完没有关闭导致的内存泄露.
  4. Bitmap没有及时调用recycle()回收导致的泄露.

5 防止OOM措施

  1. 使用更加轻量的数据结构,赋值方式 StringBuilder,SparseArray替代hashmap
  2. bitmap合理使用,lrucache机制,采用png,九宫图等格式,缩放比例,解码格式(择ARGB_8888/RBG_565/ARGB_4444/ALPHA_8,)等等
  3. 使用更加轻量的数据结构,赋值方式
  4. 合理利用强、弱引用
  5. 注意对象的生命周期等,不要被生命周期长的资源给引用
  6. 避免在onDraw方法里面执行对象的创建
  7. 注意add/remove, register/unregister, bind/unbind的成对使用. 资源及时关闭, 释放.
  8. LeakCanary工具辅助
  9. logcat、
  10. Memory Monitor、
  11. Heap Viewer、(堆内存查看工具,用于监控App的某一时刻的内存堆上的具体使用情况)
    1. Allocation Tracker、(内存分配追踪工具,用于追踪一段时间的内存分配使用情况 点击”start Allocation Tracking)
  12. DDMS

链接:https://juejin.cn/post/6844903465307602957


 一、Handler 引起的内存泄漏。 解决:将Handler声明为静态内部类,就不会持有外部类SecondActivity的引用,其生命周期就和外部类无关, 如果Handler里面需要context的话,以通过弱引用方式引用外部类

二、单例模式引起的内存泄漏。 解决:Context是ApplicationContext,由于ApplicationContext的生命周期是和app一致的,不会导致内存泄漏

三、非静态内部类创建静态实例引起的内存泄漏。 解决:把内部类修改为静态的就可以避免内存泄漏了

四、非静态匿名内部类引起的内存泄漏。 解决:将匿名内部类设置为静态的。

五、注册/反注册未成对使用引起的内存泄漏。 注册广播接受器、EventBus等,记得解绑。

六、资源对象没有关闭引起的内存泄漏。 在这些资源不使用的时候,记得调用相应的类似close()、destroy()、recycler()、release()等方法释放。

七、集合对象没有及时清理引起的内存泄漏。 通常会把一些对象装入到集合中,当不使用的时候一定要记得及时清理集合,让相关对象不再被引用。