Android性能优化 -- 内存优化

1.Android的内存管理

Android的内存管理 = 内存分配 + 内存回收(释放)

1)内存分配

对象/变量的内存分配由程序自动负责,共有三种

  • 静态分配:存在于方法区,线程共享,存储已被虚拟机加载的类信息、常量、静态变量,在编译时就已经分配好并且存在于程序整个运行期间。
  • 栈式分配:存在于栈区,线程独享,存储方法执行时的局部变量(含数据类型以及对象的引用),方法执行时,定义的局部变量,则由程序自动在栈中分配内存,方法执行结束或者超出变量区域时,则由栈自动释放该部分的内存,效率高(栈内存的分配运算内置于处理器的指令集中),但分配的内存容量有限
  • 堆式分配:存在于堆区,线程共享,存储java对象的实例和实例内的成员变量,即采用new关键字new出来的对象,实例的成员变量 = 基本数据类型、引用对象的实体,创建对象实例时,由程序分配(由Java垃圾回收管理器自动管理,不使用时则回收)

2)内存回收

内存回收主要由GC负责,常见的回收算法

  • 标记 - 清除算法:标记阶段,标记出所有需要回收的对象;清除阶段,统一清除(回收)所有被标记的对象。优点是实现简单,缺点是效率问题和空间问题,标记和清除这两个过程效率不高,而且在标记 - 清除后,会产生大量不连续的内存碎片。一般应用在对象存活率较低和垃圾回收行为频率低(如老年代)
  • 复制算法:将内存分为大小相等的两块,每次使用其中的一块,当使用的这块内存用完,就将这块内存上还存活的对象复制到另一块还没有用过的内存上,然后将使用的那块内存一次清理掉。复制算法的优点是解决了标记 - 清除算法中的效率低的问题,每次仅回收一半的区域,解决了标记 - 清除算法中产生不连续的空间碎片的问题;将已经使用内存上的存活对象移动到栈顶的指针,按顺序分配内存即可。缺点是每次使用的内存缩小为原来的一半,当对象存活率较高的时候,需要做很多的复制操作,即效率会变低。多应用在对象存活率较低,需要进行频繁垃圾回收的区域,如新年代。
  • 标记 - 整理算法:标记阶段,标记出所有需要回收的对象;整理阶段,让所有存活的对象都都向一段移动;清除阶段,统一清除这端以外的对象。优点是解决了标记 - 清除算法中清除效率低的问题,一次清除;解决了标记 - 清除算法中,空间产生不连续的碎片问题,将已使用内存上存活对象移动到了栈顶的指针,按顺序分配内存即可。缺点:步骤繁多,标记、整理、清除。应用场景:对象存活率较低并且垃圾回收行为频率较低,如老年代。
  • 分代收集算法:根据对象存活周期不同,将Java堆分为新生代和老年代。新生代:对象存活率较低、垃圾回收行为频率高;老年代:对象存活率较低,垃圾回收行为频率低。根据每块区域的特点选择对应的垃圾算法,新生代:复制算法;老年代:标记 - 清除算法、标记 - 整理算法。优点:效率高、空间利用率高,根据不同的区域特点选择不同的垃圾收集算法,一般虚拟机都采用的这种算法。

 

2.常见的内存问题和优化方案

1)内存泄漏

关于内存泄漏可以查看这篇文章Android内存泄漏

 

2)内存抖动

内存大小不断浮动的现象,原因是程序频繁的分配内存同时垃圾回收器频繁的回收内存,即大量的临时小对象频繁的创建。垃圾回收器频繁的回收内存会导致卡顿,甚至内存溢出(OOM),因为大量、临时的小对象频繁创建会导致内存碎片,使得当需要分配内存时,虽然总体上还是有剩余的内存可分配,但由于这些内存不连续,导致无法整块分配,系统则视为内存不够,从而OOM

优化方法:尽量避免频繁创建大量临时的小对象

 

3)代码质量

因为代码本身的质量(如数据结构、数据类型等)以及数量(代码的大小)可能会导致大量的内存问题,如内存占用过大,内存占用率低等问题

数据结构:使用性能高的数据结构,在Android平台端,使用Android优化后的数据结构,如SpraseArray、SpraseBooleamArray等,使用SpraseArray代替key为int的Hashmap,可省30%的内存;使用ArrayMap,可省10%的内存。传统的Hashmap在内存上的实现十分低效的原因是需为map中每项在内存中建立映射关系;而SpraseArray高效的原因是避免在系统中自动装箱key

数据类型:使用占用内存小的数据类型,尽量避免使用枚举类型,因为枚举变量占的内存大,比直接使用int类型多使用2倍内存。

数据对象引用:根据不同的场景,选择不同的引用类型(强、弱、软、虚)

 

3.常用工具

MAT(Memory Analysis Tools)、Heap Viewer、Android Studio自带的Memory Monitor等

你可能感兴趣的:(你好,Android,Android,内存优化)