您的位置:首页 > 移动开发 > Android开发

控制 Android 程序使用的内存

2014-03-12 22:29 190 查看

如何控制应用程序使用的内存?

1. 记得关闭启动的服务

当服务中的任务完成后,要记得停止该服务。可以考虑使用
IntentService
,因为
IntentService
在完成任务后会自动停止。

2. UI 不可见时释放资源

onStop
中关闭网络连接、注销广播接收器、释放传感器等资源;

onTrimMemory()
回调方法中监听
TRIM_MEMORY_UI_HIDDEN
级别的信号,此时可在 Activity 中释放 UI 使用的资源,大符减少应用占用的内存,从而避免被系统清除出内存。

3. 内存紧张时释放资源

运行中的程序,如果内存紧张,会在
onTrimMemory(int level)
回调方法中接收到以下级别的信号:

TRIM_MEMORY_RUNNING_MODERATE
:系统可用内存较低,正在杀掉 LRU 缓存中的进程。你的进程正在运行,没有被杀掉的危险。

TRIM_MEMORY_RUNNING_LOW
:系统可用内存更加紧张,程序虽然暂没有被杀死的危险,但是应该尽量释放一些资源,以提升系统的性能(这也会直接影响你程序的性能)。

TRIM_MEMORY_RUNNING_CRITICAL
:系统内存极度紧张,而 LRU 缓存中的大部分进程已被杀死,如果仍然无法获得足够的资源的话,接下来会清理掉 LRU 中的所有进程,并且开始杀死一些系统通常会保留的进程,比如后台运行的服务等。(关于进程的优先级,参考这里

当程序未在运行,保留在 LRU 缓存中时,
onTrimMemory(int level)
中会返回以下级别的信号:

TRIM_MEMORY_BACKGROUND
:系统可用内存低,而你的程序处在 LRU 的顶端,因此暂时不会被杀死,但是此时应释放一些程序再次打开时比较容易恢复的 UI 资源。

TRIM_MEMORY_MODERATE
:系统可用内存低,程序处于 LRU 的中部位置,如果内存状态得不到缓解,程序会有被杀死的可能。

TRIM_MEMORY_COMPLETE
:系统可用内存低,你的程序处于 LRU 尾部,如果系统仍然无法回收足够的内存资源,你的程序将首先被杀死。此时应释放无助于恢复程序状态的所有资源。


注:该 API 在版本 14 中加入。旧版本的
onLowMemory()
方法,大致相当于
onTrimMemory(int level)
中接收到
TRIM_MEMORY_COMPLETE
级别的信号。

另:尽管系统主要按照 LRU 中顺序来杀进程,不过系统也会考虑程序占用的内存多少,那些占用内存高的进程有更高的可能性会被首先杀死。



4. 确定你的程序应该占用多少内存

可以通过
getMemoryClass()
来获取你的程序被分配的可用内存,以 M 为单位。

你可以通过在
<application>
标签下将
largeHeap
属性设为 true 来要求更多的内存,这时通过
getLargeMemoryClass()
方法来获取可用内存。

大部分应用程序不需要使用此功能,因此使用该标签前,确认你的程序是否真的需要更多内存。使用更多内存会对整个系统的性能产生影响,而且当程序进入 LRU 时会更容易首先被系统清理掉。

5. 正确使用 Bipmap,避免浪费内存

如果你的 ImageViwe 的尺寸只有 100 * 100,那么没有必要将一张 2560 * 1600 的图片整个加载入内存。关于如何加载图片,参考这里

6. 使用 Android 提供的优化过的数据结构

如 SparseArray, SparseBooleanArray, LongSparseArray 等,相比 Java 提供的 HashMap,这些结构更节省内存。

7. 始终对内存使用情况保持关注

枚举类型 Enum 会比静态常量占用更多的内存;

Java 中每个类(包括匿名内部类)都占用至少 500 字节左右的代码;

每个类的实例会在 RAM 中占用大约 12 ~ 16 字节的内存;

每向 HashMap 中添加一个 Entry 时,新生成的 Entry 占用大约 32 个字节。

8. 谨慎使用第三方类库

这些外部类库可能原先并非针对移动平台,因此未进行过优化,在使用前应注意。另外尽量不要因为一两个特性而使用一个体积很大的类库。

9. 使用 ProGuard

使用 ProGuard 移除无用的代码并重命名一些类、字段、方法等,使你的代码更紧凑,节省内存空间。

10. 使用 zipalign

zipaligned 对最终打包的 apk 进行字节对齐。

注:Google Play 不接受未对齐过的 apk。

11. 分析内存使用情况

如果已经获得一个相对稳定的版本,应对程序整个生命周期的内存使用状况进行分析。参考这里

12. 使用多个进程

如果程序需要执行大量的后台工作,可考虑将程序分为两个进程,一个进程负责 UI,另一个进程负责后台任务。比如音乐播放器。

代码示例:

<serviceandroid:name=".PlaybackService" android:process=":background"/>


android:process属性的值以“:”开头,名称可任意选取。

在决定是否使用多进程前,应注意,一个不执行任何任务的空进程至少也要占用 1.4 MB 内存。

另外要注意进程的相互依赖性,比如如果将 ContentProvider 放在 UI 进程中,而后台任务进程也需要调用 ContentProvider,就会导致 UI 进程一直保留在 RAM 中。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: