Android基础之内存溢出

大家好,今日我讲述的是Android基础优化的内存溢出。
首先大家要清楚我们说的是内存溢出,术语来描述就是程序运行要求的内存大于虚拟机能提供的最大内存,会导致程序崩溃,也就是我们常见的OutOfMemory(OOM)错误。我们可以形象理解一下,不停向杯子里面倒水,当水超过杯子的容量后,水会溢出

关于Android内存的基础描述

如何去针对内存溢出作对应优化

Android内存的基础描述

  • Java虚拟机(Java Virtual Machine 简称JVM)是运行所有Java程序的抽象计算机,每一个Java程序都运行于自己的Java虚拟机实例中。Java虚拟机有自己完善的结构体系。然而这JVM的体系结构包含着几个重要的子系统和内存区:

    1. 垃圾回收器:负责收回堆内存(Heap)中没有被使用的对象;
    2. 类装载子系统:除了要定位和导入二进制class文件外,还必须负责验证被导入类的正确性,为类变量分配并初始化内存,以及帮助解析符号引用;
    3. 执行引擎(Execution Engine):负责执行那些包含在被装载类的方法中的指令;
    4. 运行时数据区(Java Memory Allocation Area):又叫虚拟机内存或者Java内存,虚拟机运行时需要从整个计算机内存划分一块内存区域存储许多东西。
  • java内存分区

运行时数据区即是java内存,系统根据存储数据的不同,java内存通常被划分为5个区域:程序计数器(Program Count Register)、本地方法栈(Native Stack)、方法区(Methon Area)、栈(Stack)、堆(Heap)

  • 内存管理机制

Java语言对内存的处理是:程序员无需去管理内存,因为JVM有垃圾回收(GC),会去自动进行垃圾回收。因此:
1. 垃圾回收并不会按照程序员的要求,随时进行GC。
2. 垃圾回收并不会及时的清理内存,尽管有时程序需要内存。
3. 程序员不能对垃圾回收进行控制。

这些是我觉得大家需要简单了解的基础知识,但是这里面又包含着很多更深一层的Android知识,我就不在这里一一讲述,需要的话大家对不理解的某个术语,可以自行查阅资料。

优化内存溢出

其实内存溢出,很多情况下都是移动设备的RAM分配给我们的内存空间不足导致的,但是我们市面上的不同价位不同厂商的物理内存都是可能不同的,所以我们程序需要做的是省着用。(部分方法是参考其他文章而整理)

  • 少着用

    1. 考虑使用ArrayMap/SpareseArray而不是传统的HashMap等数据结构,Android系统为移动系统设计的容器ArrayMap更加高效,占用内存更少,因为HashMap需要一个额外的实例对象来记录Mapping的操作。而SparesArray高效的避免了key和value的自动装箱,而且避免了装箱后的解箱。
    2. Android官方培训课程提到过“Enums often require more than twice as much memory as static constants. You should strictly avoid using enums on Android.” 请避免在Android里面使用到枚举。
    3. 减少Bitmap对象的内存占用。包括inSampleSize:缩放比例,在把图片载入内存之前,我们需要计算一个合适的缩放比例,避免不必要的大图载入。decode format:解码格式,选择ARGB_8888/RBG_565/ARGB_4444/ALPHA_8,存在很大差异。使用更小的图片:在设计图片资源的时候,我们要考虑图片是否存在可以压缩的空间,是否能使用更小的图片,使用小图在xml加载资源时就不会在初始化视图因为内存不足而发生InflationException,其根本原因就是发生了OOM。
    4. StringBuilder。如果代码中有大量字符串拼接操作,使用StringBuilder代替”+”。
  • 用了再用

    1. 复用系统自带的资源:Android系统本身内置了很多的资源,例如字符串/颜色/图片/动画/样式以及简单布局等等,这些资源都可以在应用程序中直接引用。这样做不仅仅可以减少应用程序的自身负重,减小APK的大小,另外还可以一定程度上减少内存的开销,复用性更好。但是也有必要留意Android系统的版本差异性,对那些不同系统版本上表现存在很大差异,不符合需求的情况,还是需要应用程序自身内置进去。
    2. 在ListView/GridView等出现大量重复子组件的视图里面对ConvertView的复用
    3. Bitmap对象的复用:利用inBitmap的高级特性提高Android系统在Bitmap分配与释放执行效率上的提升(3.0以及4.4以后存在一些使用限制上的差异)。使用inBitmap属性可以告知Bitmap解码器去尝试使用已经存在的内存区域,新解码的bitmap会尝试去使用之前那张bitmap在Heap中所占据的pixel data内存区域,而不是去问内存重新申请一块区域来存放bitmap。利用这种特性,即使是上千张的图片,也只会仅仅只需要占用屏幕所能够显示的图片数量的内存大小。
    4. 避免在onDraw方法里面执行对象的创建:类似onDraw等频繁调用的方法,一定需要注意避免在这里做创建对象的操作,因为他会迅速增加内存的使用,而且很容易引起频繁的GC,甚至是内存抖动。
    5. 对象池的使用:如果某个对象在创建时,需要较大的资源开销,那么可以将其放入对象池,即将对象保存起来,下次需要时直接取出使用,而不用再次创建对象。当然,维护对象池也需要一定开销,故要衡量。
    6. 线程池:与对象池差不多,将线程对象放在池中供反复使用,减少反复创建线程的开销。
  • 用完整理好

    1. 注意临时Bitmap对象的及时回收:虽然在大多数情况下,我们会对Bitmap增加缓存机制,但是在某些时候,部分Bitmap是需要及时回收的。
    2. 地图定位显示等外部SDK资源引用,在使用完之后,主动将地图对象的生命周期主动结束并设空。
      (个人觉得这部分与内存泄露为共同内容,还有这里不能使用“用完清干净”清这个动词,因为上文我们说到,我们程序员并不能主动对JAVA程序的垃圾回收进行任何操作,所以我们用“整理”这个动词)

总结:这篇简单说了关于内存溢出的优化。这是Android中级工程师面试经常被问到的一个问题。大家是需要了解并学会运用的。而我介绍了“怎么样”去做,至于“为什么”,需要同学们自主去翻阅资料。由于优化部分的内容是参考部分博客整理的,请大家见谅,谢谢大家!

Android基础之内存溢出_第1张图片

你可能感兴趣的:(Android,android,内存溢出,优化,面试)