在之前的文章中我们总结过跟Android 内存相关的知识或者问题,这里先列举一下:
2. Java 对象引用方式 —— 强引用、软引用、弱引用和虚引用
3. Android Studio 使用Memory Monitor进行内存泄露分析
5. Android 常见 Memory Leak 原因及解决办法总结
从之前整理的内存来看,我们首先需要了解的就是Java内存使用及回收相关的知识,然后在Android上涉及内存管理问题主要就是内存抖动、内存泄漏、内存溢出。
本文我们针对性能优化再次做一下Android开发时我们能对内存方面进行优化的内容,虽然有点赘述,但是希望能温故知新。
首先我们先了解一下Android的内存分配策略,然后再谈一下如何优化内存问题。
一、Android 内存策略
1. Android 进程的内存策略
进程的内存分配策略为:由 ActivityManagerService
集中管理所有进程的内存分配。
进程的内存回收策略为:
首先 Application Framework 决定回收的类型,当进程的内存空间紧张时会按照进程优先级由低到高的顺序自动回收进程及内存。
Android Framework将进程分为5个优先级,具体如下:
真正执行回收进程的操作的是 Linux 内核。
梳理一下整体流程:
1. ActivityManagerService 对所有进程进行评分。
2. 更新评分到 Linux 内核。
3. 由 Linux 内核完成真正的内存回收。
2. Android 对象、变量的内存策略
Android 对对象、变量的内存策略和Java是一样的,对内存的管理即为 对象&变量的内存分配和内存释放。下面我们讲一下内存分配和内存释放的策略:
a. 内存分配策略
对象&变量的内存分配有系统负责,共有三种:静态分配、栈式分配、堆式分配,分别面向静态变量,动态变量和对象实例。
b. 内存释放策略
对象&变量的内存释放由Java的垃圾回收器GC负责。
二、常见的内存问题及优化方案
常见的内存问题如下: 内存抖动、内存泄漏、内存溢出。
1. 内存泄漏
内存泄漏的定义是:内存中存在已经不再使用,但是并未回收的对象。表现的现象为:内存出现抖动和可用内存逐渐变少。存在的危害是:会造成内存不足,GC频繁,甚至出现OOM。
常见引发内存泄漏的主要情况有如下情况:
1. static 关键字修饰的成员变量
核心点:被static修饰过的成员变量的生命周期 = 应用程序的生命周期。
泄漏原因:若被static修饰的成员变量引用短生命周期的实例,则容易出现该成员变量的生命周期 > 引用实例生命周期的情况,当引用实例需结束生命周期销毁时,会因静态变量的持有而无法被回收,从而出现内存泄露。
解决方案:
a. 尽量避免static成员变量引用资源消耗过多的实例(若需引用Context,则尽量使用Application的Context)。
b. 使用弱引用WeakReference代替强引用持有实例。
经典案例 ==》单例模式
核心点:单例模式 其生命周期的长度 = 应用程序的生命周期
泄漏原因:若1个对象已不需再使用 而单例对象还持有该对象的引用,那么该对象将不能被正常回收 从而 导致内存泄漏
解决方案:单例模式引用的对象的生命周期 = 应用的生命周期。 或者编写代码保证在合适的时机释放资源。
2. 非静态内部类/匿名类
核心点:非静态内部类默认持有外部类的引用,可能会导致外部类对象无法释放,造成内存泄漏。
解决方案:使用静态内部类。
经典案例 ==》Runnable、AsyncTask、Thread、Handler 等类
3. 资源使用后未关闭
泄露原因:对于资源的使用(如 广播BraodcastReceiver
、文件流File
、数据库游标Cursor
、),若在Activity
销毁时没有及时关闭或注销这些资源,则这些资源将不会被回收,从而造成内存泄漏。
Activity
销毁时 及时关闭 / 注销资源2. 内存抖动
核心原因:频繁创建大量、临时的小对象。
排查方向:优先寻找循环或者频繁调用的地方进行排查。
优化方案:避免创建大量、临时的小对象。
3. 内存溢出
请参考:Android OOM 引发的思考。这里就不过多整理了。