记录一次Android内存优化

记录一次内存优化的过程,总结经验,若有错误纰漏欢迎指出。本次优化主要分为两部分:内存泄漏问题和内存不合理的开销。本次主要使用的分析工具为 Android Profiler ,具体使用方法文章众多,不做阐述。

内存泄漏

内存泄漏可以理解为一个对象存在的生命周期大于实际期望的生命周期。如 Activity 退出后仍被单例对象引用。

案例1:OpenGL 纹理重复创建

实际问题:项目中一个动画效果使用 OpenGL 实现,每次创建动画都会调用 glGenTextures() 重新生成纹理、分配 ID,导致内存泄漏。

解决办法:一次创建好纹理后不再重复创建。

NOTE:虽然内存不会因为动画创建而持续增长,但仍有存疑:第一次创建好的纹理是否也无法在页面退出后正确释放。

案例2:互相引用

实际问题:Activity 中各种 Manager 与 Activity 相互强引用,Activity 无法释放导致泄漏。

解决办法:a)Manager 使用弱引用来引用 Activity。b)可手动管理释放 Manager 对 Activity 的引用。

案例3:注册监听后没有正确释放

实际问题:在 Activity 中注册 PhoneStateListener ,Activity 销毁后没有移除注册。典型的匿名内部类、非静态内部类的泄漏问题。

解决办法:页面退出时移除注册 telephonyManager.listen(mOnePhoneStateListener, PhoneStateListener.LISTEN_NONE);

不合理开销

案例1:视图懒加载

实际问题:引导蒙层、错误视图等都使用了尺寸较大的图片,而引导蒙层用户只有第一次使用功能时需要展示,错误视图如在成功加载数据后不会有机会展示。

解决办法:使用 ViewStub 懒加载,而非 VISIBLE、GONE 控制展示与否。

案例2:减少不必要的 Bitmap 开销

设计可能会给出组合或层叠两张或多张图片的 UI 效果。这些 Bitmap 都是占内存的,尽量使用一张图搞定。

资源文件只打包了xxhdpi的,较大的图片在适配不同大小的控件、屏幕时使用 Glide 加载,优化图片的内存占用。

案例3:默认图、占位图的释放

在请求服务端图片资源成功前、高斯模糊完成展示前,通常会先使用一张图片去做默认的展示,在上诉操作完成并展示后释放掉不再需要的默认图。


上诉为实际中碰到的案例,总结问题模式:

1)OpenGL 不要重复创建纹理。

2)其他类持有 Context 对象 (非 ApplicationContext)请使用弱引用,否则需要手动释放对 Context 的引用。

3)注意匿名内部类、非静态内部类潜在的泄漏模式。

4)视图懒加载,使用 ViewStub 在需要的时候加载视图。

5)不要使用层叠 Bitmap 实现 UI 效果,会多出一倍的内存开销。

6)使用 Glide 优化图片加载的内存使用。

7)较大的默认图、占位图手动释放。

推荐阅读 更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim 阅读 168,405 评论 26 707
  • Android 内存管理的目的 内存管理的目的就是让我们在开发中怎么有效的避免我们的应用出现内存泄漏的问题。简单粗...
    晨光光 阅读 1,193 评论 1 4
  • 001曾经也是一个不撞南墙不回头的少女,曾经也说过“我肯定不会怎样怎样”,“打死也不怎样怎样”这样的坚决的话,曾经...
    小碗月牙 阅读 265 评论 2 2
  • 今天早上上班前,将最近收拾出来的户外背包和帽子挂到南海大道下的爱心墙上。刚刚挂完转身就听到后面有个老阿姨说:“这个...
    悠悠心旅 阅读 288 评论 0 0
  • 天很冷,刺骨的北风“嗖嗖”地直往脖子里钻,吹乱了我的头发。我缩着身子,手插在口袋里,冰凉的指尖,握成拳头,却...
    张玲芳 阅读 158 评论 0 2