—— 在各种帖子中,我们经常能看到类似说 “内存用的多才正常,内存就是拿来用的,搞精简剩那么多内存在那干嘛?” 的言论。这些言论或多或少缺乏严谨性。下面我会尽可能用较为简单的描述让各位对自己手机的内存管理(主要是虚拟内存)有个基本的认识,新人第一次写科普,如有错误还请各位大佬在评论区指出
—————分割线—————
注:本文中所有的”内存”均指人们常说的”运行内存”也就是”RAM”而非存储空间!
—————分割线—————
首先,我们来认识一些概念和专业名词
1.虚拟内存:
虚拟内存是现代操作系统普遍使用的一种内存管理技术,目前常用的是页式虚拟内存管理,以页(通常是4KB)为最小粒度来管理内存的分配、回收、交换等。
2.SWAP:
SWAP是虚拟内存技术的一部分,在硬盘上划分空间用于交换内存页,说人话就是把内存中的数据移动到硬盘上以腾出物理内存。Windows上也有类似的功能”分页文件”。但与Linux不同的是,Windows对分页文件是强依赖的,关掉会有大问题,详情见本文末尾的番外篇。
3.ZRAM:
ZRAM是SWAP的另一种实现,不在硬盘空间而是直接在内存中划分空间用来交换内存页,使用LZ4/ZSTD等压缩算法对内存数据进行压缩以腾出物理内存。
4.ZRAM Writeback
ZRAM Writeback是ZRAM的拓展功能,与SWAP一样会在硬盘空间上创建交换文件用于交换内存页,不同的点在于ZRAM Writeback交换的是压缩后的内存数据。写入控制逻辑运行在用户层而非内核中,具体策略由系统厂商决定,故本文不做讨论。
5.直接回收与异步回收
内存回收的两种方式,异步回收在后台线程运行,不影响当前进程,对性能和流畅度影响较小,但回收速度慢;直接回收速度快,但会阻塞当前进程,实际表现为软件界面卡住一段时间(通常很短),对性能和流畅度影响较大。
—————分割线—————
首先来回答标题的”内存用的越多越好?”,这句话对吗?对,但不全对。
内存确实是拿来用的,但要知道一点,要用内存的并不只有操作系统和用户的软件,还有一个大头就是文件缓存,几乎所有操作系统都有文件缓存机制,从硬盘/闪存中读取的文件会缓存在内存中,下次调用时就不需要再从硬盘/闪存读取而是直接调用文件缓存以加快速度。在内存不足时文件缓存能够被快速释放腾出内存以供分配,因此这些能够快速回收的内存与空闲内存均被内核当做”可用内存”。而你在系统后台界面和各个软件(如DEV Check)中看到的都不是”空闲内存”而是内核计算得出的”可用内存”或软件自身算法计算得出的”可用内存”。
如图在内核的meminfo中”可用内存”≠”空闲内存”,”空闲内存”是真正没有被任何进程或文件所占用的未分配的内存,而”可用内存”则是可用于分配的内存(其大小是一个估测值,主要由文件缓存和空闲内存中Low水位线以上的部分以及其它可快速回收的内存项决定)
数据来源:/proc/meminfo
所以即便你在系统后台的内存信息或各软件中看到内存还剩很多,那也并不能代表内存没得到充分利用。而搞精简搞优化的那部分人比如我追求的则是降低系统自身的内存占用,好腾出更多内存供用户应用使用,与”内存用的多才正常,内存就是拿来用的”的观点并不冲突。
—————分割线—————
进阶教程——控制内存回收与ZRAM的积极性:
在拥有ROOT权限的前提下,我们可以修改以下内核参数来控制内存回收与ZRAM的积极性。
1. vm.watermark_scale_factor:
控制内存水位线之间的间隔,调节范围为1~1000(对应0.01%至10%的总内存大小)。值太小会频繁触发直接回收导致卡顿,值太大会造成内存浪费,建议设置为100(总内存的1%)。
内核定义了min/low/high三条水位线,当空闲内存(注意是”空闲内存”而不是”可用内存”)低于low水位线时内核就会唤醒kswapd异步回收内存(将数据交换至ZRAM/SWAP并回收文件缓存),直到空闲内存高于high水位线就停止;当空闲内存低于min水位线时会触发直接回收。min水位线的值由内核根据总内存大小与vm.min_free_kbytes计算比较得出,不建议修改该参数保持默认值就好。
2. vm.extra_free_kbytes:
额外保留的内存,会在min和low水位线之间增加设定的值,值太小会频繁触发直接回收导致卡顿,值太大会造成内存浪费,建议设置为总内存大小的1~2%,以KB为单位。
3. vm.swappiness:
控制内核内存不足时(低于low水位线)在交换页面至ZRAM/SWAP与回收文件缓存之间的偏向,值的范围为0~200,对于老内核范围为0~100。值越小越倾向于回收文件缓存,值越大越倾向于使用ZRAM/SWAP。
以上内核参数可在Scene中修改,也可以root权限执行以下命令修改:
echo 100 >/proc/sys/vm/watermark_scale_factor
echo 131072 >/proc/sys/vm/extra_free_kbytes
echo 100 >/proc/sys/vm/swappiness
– 如果你追求保留更多的后台,可降低extra_free_kbytes与watermark_scale_factor的值,适量增大swappiness的值。
– 如果你追求更高的流畅度,可增加extra_free_kbytes与watermark_scale_factor的值,同时将swappiness调整到较为平衡的值。
– 如果你既要又要,那就换内存更大的手机
—————分割线—————
LMK与杀后台:
从Android 9起,Google开始抛弃内核自带的LMK转为使用作为系统守护进程运行的LMKD,因此杀后台与内核本身关系就不大了,主要取决于各厂商怎么配置LMKD/引入其它杀后台机制。对于MIUI而言,除了配置LMKD外,在”电量与性能”与”framework系统框架”中均有杀后台相关代码。如果你不想用厂商额外引入的杀后台机制想自己配置LMKD,那么可用使用LSPosed模块”AppRetention”来屏蔽厂商的杀后台机制。
然后根据Google的文档来配置LMKD:查看链接
—————分割线—————
番外篇——有关Windows分页文件Pagefile.sys与虚拟内存地址分配的额外知识:
Windows采用两阶段内存分配(保留+提交),在提交阶段必须确保物理地址(物理内存或分页文件)的映射。分页文件作为系统提交限制的组成部分,直接决定了系统可支持的虚拟内存总量(在Windows任务管理器的内存信息卡页面上有”已提交”这个数据项,斜杠左侧是所有程序申请的内存大小之和,右侧是总虚拟内存大小,其值=物理内存大小+分页文件大小,其中分页文件由系统动态划分)
Windows任务管理器的内存信息
你可以简单认为在Windows上程序申请多少内存系统就会把对应大小的物理地址划分给程序,划分后其它程序就无法使用这片内存空间,而程序申请的内存大小又普遍高于其实际用到的大小,因此在关闭分页文件的情况下会出现物理内存还剩很多但打开新的程序仍提示内存不足的情况。而在Linux上则没这个问题,Linux采用延迟分配策略,仅当进程实际访问内存时才分配物理内存地址,至于程序申请的内存Linux则是分配的”真”虚拟地址,虚拟内存地址的限制则是由”vm.overcommit_memory”内核参数决定,在我们所用的Android手机上虚拟内存的分配限制”overcommit_memory”默认值为1,也就是无视虚拟内存限制允许分配全部物理内存。
在Scene的SWAP管理页面可以看到我手机上所有进程申请的内存大小高达208GB!但物理内存没用完因此我还可以继续开新的软件。
至于为什么Windows不改成跟Linux一样或类似的机制那我也不知道,只能认为是Windows的历史包袱太重了(与之对应的是WIN的传奇级兼容性)
暂无评论内容