Android 内存管理 15 个要点

一、什么是内存泄漏?

内存泄漏(Memory Leak)是指程序中己动态分配的堆内存由于某种原因程序未释放或无法释放,造成系统内存的浪费,导致程序运行速度减慢甚至系统崩溃等严重后果。

虽然 Android 的 Dalvik 虚拟机扮演了常规的垃圾回收角色,Dalvik 的 GC 会自动把离开活动线程的对象进行回收,但是 App 的内存分配与释放的时机和地点依然不可忽视。为了让 GC 能够从 App 中及时回收内存,我们需要注意避免内存泄漏并且在适当的时机来释放引用对象。

二、如何管理内存?

1. 珍惜 Services 资源
  • 当你启动一个 Service,系统会倾向为了保留这个 Service 而一直保留 Service 所在的进程。

  • Service 除非被触发执行一个任务,否则应该处于非运行状态的。同时要注意,当这个 Service 已经完成任务之后因为停止 Service 失败而引起的泄漏。

  • 限制你的 Service 的最好办法是使用 IntentService,它会在处理完自己的 intent 任务之后尽快结束自己。

2. 当 UI 隐藏时释放内存

为了能够接收到用户离开你的 UI 时的通知,需要实现 Activity 类里面的 onTrimMemory() 回调方法。应该使用这个方法来监听到 TRIM_MEMORY_UI_HIDDEN 级别的回调,此时意味着你的 UI 已经隐藏,你应该释放那些仅仅被你的 UI 使用的资源。

注意:应用仅仅会在所有 UI 组件被隐藏时接受到 onTrimMemory() 的回调并带有参数 TRIM_MEMORY_UI_HIDDEN。这点与 onStop() 回调是不同的,onStop() 会在 Activity 的实例隐藏时执行。例如,当用户从你的 App 的某个 Activity 跳转到另一个 Activity 时,onStop() 会被执行。这时应该在此回调中释放 Activity 的资源,例如,网络连接、unregister 广播接受者等。除非接受到 onTrimMemory(TRIM_MEMORY_UI_HIDDEN) 的回调,否则不应该释放你的 UI 资源。**

3. 当内存紧张时释放部分内存
4. 检查你应该使用多少内存

可以通过调用 getMemoryClass() 来获取你的 App 的可用 heap 大小。特殊情况下,可以通过在 manifest 的 application 标签下添加 largeHeap = true 的属性来声明一个更大 heap 空间。那为什么不总是申请更大的 heap 空间呢?这是因为使用额外的内存会影响系统整体的用户体验,并且使 GC 的每次运行时间更长,任务切换时,系统的性能大打折扣。

5. 避免 bitmaps 的浪费

当你加载一个 bitmap 时,仅仅需要保留适配当前屏幕设备分辨率的数据即可。如果你的应用中需要使用图片加载的功能,建议使用成熟的 ImageLoader 框架,如 Glide、Picasso、Fresco 等,这样能避免加载图片时的很多问题。

6. 使用优化的数据容器

利用 Android Framework 里面优化过的容器类型,例如:SparseArray,SparseBooleanArray、LongSparseArray。通常的 HashMap 的实现方式更加消耗内存,因为它需要一个额外的实例对象来记录 Mapping 操作。另外,SparseArray 更加高效在于它们避免了对 key 与 value 的 autobox 自动装箱,并且避免了装箱后的解箱。

7. 请注意内存开销

例如:Enums 枚举的内存消耗通常是 static constants 静态常量的 2 倍,应该尽量避免在 Android 上使用 enums。

8. 请勿滥用代码 “抽象”
9. 为序列化的数据使用 nano protobufs
10. 避免使用依赖注入框架
11. 谨慎使用外部库
12. 优化整体性能
13. 使用 ProGuard 来剔除不需要的代码
14. 对最终的 APK 使用 zipalign
15. 使用多进程

当你的 App 需要在后台运行与前台一样的大量的任务时,可以考虑使用这个技术:通过把你的 App 组件切分成多个组件,运行在不同的进程中。一个典型的例子是创建一个长时间后台播放的 Music Player,类似这样的 App 可以切分成 2 个进程:一个用来操作 UI,另一个用来后台的 Service。

可以通过在 manifest 文件中声明 android:process 属性来实现某个组件运行在另外一个进程的操作:

        

你可能感兴趣的:(Android 内存管理 15 个要点)