Android性能优化之内存优化

708 阅读6分钟

本文正在参加「金石计划」

Android内存优化是一项重要的任务,因为内存是Android系统中最关键的资源之一。写出一个app容易,写好一个app不容易,因为要做大量的优化,并且是持续的优化。关于内存优化,我们需要了解哪些知识呢?什么是内存泄漏?如何检测内存泄漏?什么是OOM内存溢出?如何使用Android Studio自带的内存分析工具?带着这几个问题我们就进入了正题。

什么是内存泄漏

内存泄漏是指在计算机程序中,分配的内存空间没有被正确释放或回收的情况。这种情况会导致程序占用越来越多的内存,直到最终程序崩溃或系统资源不足。

内存泄漏不是我们Android特有的,C/C++语言写的程序也会内存泄漏,我们Java中的内存泄漏相对来说比较容易发现和解决。Java的内存泄漏发生在强引用中,Java的引用总共有4种,强引用、软引用、弱引用和虚引用,你声明变量时不指定引用类型就是强引用。我们知道Java是有一个垃圾回收机制GC的,一个变量被其他类引用,就会增加一个引用计数,只有当这个变量的引用计数降为0时,才会触发GC的回收。因为当这个变量还被引用的时候,GC是不能回收掉这部分内存的,因为可能造成程序错误。而内存泄漏则发生在一个短周期的类里面引用了一个长周期的变量,导致了短周期的这个类的引用计数为0本应该被回收,但是拖泥带水地引用了一个还不能被回收的变量,比如一个耗时的文件读写操作。这个时候就导致了GC也没有回收这个短周期的类,比如已经被finish的Activity。

如何检测内存泄漏

检测Android程序的内存泄漏其实很简单,通常我们使用的是LeakCanary。只需要在app模块的build.gradle中添加LeakCanary的依赖即可。

// 内存泄漏检测
debugImplementation("com.squareup.leakcanary:leakcanary-android:2.10")

然后我们在打debug包的时候就会附带安装一个出详细内存泄漏报告的一个名叫Leaks的app了。当app发生内存泄漏的时候,Leaks这个app就会自动帮你记录内存泄漏了。

什么是内存溢出

内存溢出是指程序在运行时需要的内存超出了系统所能提供的可用内存空间,导致程序崩溃或出现异常。在计算机程序中,内存通常被用来存储程序的数据和指令,如果程序需要的内存超过了系统所能提供的内存空间,就会导致内存溢出的问题。

在Android手机系统中,也给每一个应用进程设置了一个能分配的最大内存上限。也正是因为这个上限,导致了一些动歪脑筋的应用开发者,给app开多个进程以抢占更多的内存资源。但是,尽管这样,你代码写的不好,难道你就不内存溢出了吗?答案是否定的,就算把整个手机的内存都给你,也防止不了猪队友写的垃圾代码导致的内存溢出。故意写死循环导致程序卡死的这种情况就不是水平问题而上升到人品问题了。

在Android中内存溢出通常是由于加载大量Bitmap,而又没有及时回收导致的。早期的开发者使用软引用解决OOM问题,而现在这个框架横生的时代,我们不用自己去解决图片加载的OOM问题了,我们可以直接使用像Glide这样的图片加载框架,它会自动帮我们处理LruCache的问题,当内存不够用的时候,按时间轴最早加载的那部分Bitmap会被释放掉。

使用meminfo统计内存使用情况

adb shell "dumpsys meminfo"

执行这个命令看下你的应用的内存使用情况。我们再来看下与进程相关的VSS、RSS、PSS、USS这几个概念。

  1. VSS(Virtual Set Size):进程保留供其使用的虚拟内存量。
  2. RSS(Resident Set Size):进程当前使用的物理内存量,这包括私有和共享内存段。
  3. PSS(Proportional Set Size):进程正在使用的内存量,这包括私有和共享内存段。在共享同一内存段的所有进程之间按比例共享。该指标通常用于识别多进程环境中进程的实际内存使用情况。
  4. USS(Unique Set Size):一个进程独占使用的内存量,不与任何其他进程共享。

翻译成中文,VSS虚集合大小、RSS常驻集合大小、PSS比例集合大小和USS独占集合大小。VSS这个跟我们实际物理内存占用关系并不大,比如一块内存区域被多个变量引用,而实际这个VSS虚拟集合会重复统计,这个就是物理内存和程序虚拟内存的区别。RSS没有将共享内存大小平分到使用共享内存的进程上,由于共享内存只会占用一份内存,所以如果你把进程的RSS相加,就会超出很多。而PSS通常被用来衡量应用实际的内存使用情况。USS独立内存,统计出来就不会包含多进程共享的那部分内存。

使用Android Studio的Profiler对内存进行分析

使用Android Studio自带的内存分析工具分析内存使用情况,具体打开方式View > Tool Windows > Profiler

Profiler 选择MEMORY选项可以看实时内存使用情况。然后切到CPU选项,选择Java/Kotlin Method Trace点击RECORD进行录制,可以分析该段时间的方法调用情况。

总结

内存优化主要还是要靠开发中自行避免,在写的时候就避免内存问题是最好的,防范于未然。避免写出内存泄漏的代码,比如谨慎使用static关键字,常量和工具方法可用。实在是遇到了可能造成内存泄漏的代码,要转换成弱引用WeakReference。避免写出内存溢出的代码,比如,使用Glide帮你处理图片加载,尽量不要在大量调用的代码块(如循环或View的onDraw)里面创建对象。仔细审查代码也能避免内存问题的出现,在测试中也能发现内存问题,应用上线后在产品运营的分析中也还能发现,但是它们所带来的结果是不一样的。在整个环节的越早期处理掉内存问题越好,越到后面的环节,付出的代价如时间成本就会越大。