安卓手机的「内存扩展」是什么原理?
可以自己判断安卓手机是否需要开启“内存拓展”:在最高强度使用下,如果free命令显示的Swap用量仍不超过物理内存的一半,那应该不需要启用硬盘上的“虚拟内存”。比如下图里8G RAM手机的Swap用量不超过700M,未达到7.3G的一半,说明zram都没有用满,更用不上“虚拟内存”。那Swap是什么意思?为什么是一半?zram又是什么?请听我细细道来~

应对内存不足的办法无非开源、节流两种,前者对应“虚拟内存”(paging),后者对应内存压缩(memory compression)。
在Linux内核中,内存中的数据都已经分块成固定大小的内存分页(相应的内存管理模式也称为virtual memory,但本文的“虚拟内存”不取此义;安卓15以上要求16k的内存分页大小,而非传统的4k),这是内存数据的最小单元,就像硬盘的逻辑扇区一样。可见,如果物理内存容量不足,就可以将暂时用不着的内存分页移动至硬盘,需要时再转回物理内存。将内存分页在内存条与硬盘之间进行“交换”(Linux内核称之为Swap),这就是“虚拟内存”的工作方式。Linux内核既可以把内存分页放在一个特定的文件之中(就像Windows的C:\pagefile.sys一样),也可以将某个硬盘分区用于Swap,前者更灵活,后者更适用于机械硬盘这类不同分区速度有别的硬盘。
很多安卓手机的“内存拓展”,实际上应该就是内置存储里的分页文件,不同的“内存拓展”大小,对应的就是不同大小的分页文件(如果开启zswap内存压缩,分页文件可以更小,详见后文),可见“内存拓展”越大,可用的存储空间就越小。而且在高强度使用下,“内存拓展”的使用无疑会缩短闪存寿命,比如2021年左右曾有过关于8G内存Macbook硬盘寿命的大量讨论,这可能就与zswap虚拟内存有关。再加上内置存储的读写速度远低于RAM,“内存拓展”只是后台保活、性能、闪存寿命之间的权衡罢了。要不是很多手机不开放闪存寿命显示、要不是智能手机的快消品属性过强,用户恐怕也不会默许手机厂商默认开启“内存拓展”的行为。

除了虚拟内存之外,内存压缩也是常用技术,即把暂时用不着的内存分页进行压缩之后,重新放入物理内存之中(对应Linux内核的zram功能),或者移入硬盘中(对应Linux内核的zswap功能)。zram可以增加当前可用内存容量,zswap可以缩小写入硬盘的数据大小,提升虚拟内存性能。尽管数据压缩会带来一定的CPU性能开销,但总体而言利大于弊。

安卓4.4以上支持zram,根据使用经验,近五六年的主流安卓系统都已默认开启zram,在“设置”的“内存使用情况”页面可以看到一些应用的Z-Ram使用量。在GNU/Linux系统、以及安卓系统总中,free命令输出结果里的Swap栏所展示的总容量与使用量,是硬盘虚拟内存(无论是否开启zswap)与zram的总和,而具体的zram大小需要通过内核日志或/sys下的文件查看,这在没有root的安卓系统下是做不到的。
但实际上,由于压缩算法的压缩率有限(一般是2:1),设置太高的zram可压缩容量上限没有实际意义,因此zram的可压缩大小一般设为物理内存的一半,systemd-zram-generator、AOSP安卓12、以及AOSP安卓16都是如此,比如物理内存有8G,则系统设定为其中有4G可被压缩,此时如果没有开启硬盘虚拟内存,free -h命令输出的Swap - total就会显示为4G;其中,-h参数表示显示可读性强的容量单位(human-readable)而非默认的字节单位。

如果Swap - total大于物理内存容量的一半,既可能是系统设定的zram可压缩容量较大,也可能是系统已经开启了硬盘虚拟内存。但在同时启用zram与硬盘虚拟内存的情况下,zram的优先级一般设为更高值(优先级priority可以在内核日志中查看),所以如果在常用软件全驻后台、前台运行重量级软件这样的超高使用强度下,Swap使用量都不超过物理内存的一半,那么基本可能肯定,自己手机的物理内存容量是够用的,不需要开启硬盘虚拟内存。
P.S. 我的Moto手机即使开启“内存拓展”,Swap总容量也没有变化,只有存储占用增加,logcat显示ExtRam : Supported:true, MotoSwapSupported:true,不解……会不会只是生成特定大小的分页文件,但只有检测到内存满了才启用?这么智能的吗 😂