ZRAM那点事 -- ZRAM和ZSMALLOC简介及3个问题的改进和1个提高

2020-02-27 1655浏览

  • 1.ZRAM那点事 ZRAM和ZSMALLOC简介及3个问题的改进和1个提高 朱辉 zhuhui@xiaomi.com teawater.github.io
  • 2.什么是ZRAM? • Linux内核中提供的虚拟磁盘。 • 将写入的页面压缩并分配内存存储在系统中。 • 主要用来作为SWAP设备。 • 常用在用闪存作为存储空间的设备上。
  • 3.为什么用ZRAM?(见下图) • 设备上可以不再需要开其他的SWAP 。(区别于 ZSWAP) 节省了闪存的寿命。 节省了硬盘空间。 节省了BLOCK IO。 • 通过压缩节省内存。 Android下可用来提高进程保活度。
  • 4.LRU Shrinker
  • 5.ZRAM
  • 6.Android 无SWAP
  • 7.Android有SWAP
  • 8.什么是ZSMALLOC?(见下图) • 针对内存压缩场景设计的内存分配器。 类似其的还有ZBUD和Z3FOLD。 • ZRAM直接使用ZSMALLOC。 ZSWAP通过ZPOOL框架使用其。
  • 9.ZSMALLOC内部结构(见下图) • 基本结构: 每个对ZSMALLOC的使用者会申请一个zs_pool。 每个zs_pool根据存储数据的大小分出若干size_class。 每个size_class中根据元素占有状态分出4个fullness_list。 每个fullness_list保存若干zspage,每个zspage由一个到几个几个不连续page组成。 每个zspage(由最多4个非连续page组成)保存若干储存对象obj,ZRAM中每个page最终会被 保存为一个obj。 ZRAM通过handle以映射的形式访问某个obj,因为是映射式的访问,highzone page也是可以 使用的。(今年还有修改,后面会提到) • 比较重要: 页面被压缩后存储为一个obj,被存于由页面组成的zspage中,外面访问其要通过handle。 • 实际观测ZSMALLOC内部结构可在配置内核中打开CONFIG_ZSMALLOC_STAT=y。 访问/sys/kernel/debug/zsmalloc/zram0/classes就可查看ZSMALLOC中的内部信息。
  • 10.
  • 11.注意查找彩蛋
  • 12.ZRAM使用中出现3大问题 Minchan Kim于2015年提出: • 外部碎片 • 不能移动的页 • 内部碎片 这三个问题有一定相关性,并且都需要在ZSMALLOC中进行修复。 从去年开始层层修复到今年在Upstream上全部修复完成。
  • 13.内部碎片(见下图) • 开ZRAM时间长了以后感觉内存还是不够。杀掉一堆 进程后又感觉好点了。但是很快又不够了。
  • 14.内部碎片的成因(见下图) • 针对一个尺寸的size_class中实际存储数据的是obj。 • 而obj被存储在zspage中,随着使用会不断有分配和 释放,如果没有相应碎片处理,则会出现很多碎片 化的zspage。 • 内部碎片导致ZRAM内存使用率变差,影响ZRAM效 果。 • 注意这张图和前面的图不同,因为前面的图是根据 修正后来做的。
  • 15.
  • 16.fullness_list最早的抗碎页机制(见下图) • ZS_EMPTY,ZS_ALMOST_EMPTY, ZS_ALMOST_FULL,ZS_FULL这4个zspage的列表。 每个列表储存的ZSPAGE是其标记的所处状况。 使用的时候优先从ZS_ALMOST_FULL中找ZSPAGE。 • 缺点:完全被动,虽然分配抗碎页,但是释放还是 碎片化的。
  • 17.
  • 18.__zs_compact主动碎片清理(1)准备工作(见下 图) • 将handle从存储指向obj的数据改为指向obj的指针。 • 这样zsmalloc内部可以根据obj位置的变化修改handle 内容,ZRAM还可以找到某个页面对应的obj。
  • 19.
  • 20.
  • 21.__zs_compact主动碎片清理(2)实际处理(见下 图) 对一个size_class进行如下处理: 按照先ZS_ALMOST_EMPTY,后ZS_ALMOST_FULL的顺序抽出一个 来源zspage。 然后按照先ZS_ALMOST_FULL,后ZS_ALMOST_EMPTY的顺序抽出 一个目标zspage。 把来源zspage中的obj依次移动到目标zspage中。 将已经空了的来源zspage释放掉,再按照刚才的方法取得一个来 源zspage。 将满了的目标zspage加入ZS_FULL,再按照刚才的方法取得一个目 标zspage。 如此循环,直到无法取得来源zspage或者目标zspage。
  • 22.
  • 23.__zs_compact主动碎片清理(3)调用处理(见下 图) • zs_compact会依次调用__zs_compact对一个zs_pool中 的每个size_class进行清理。 • 需要的时候可通过sysfs接口调用清理。 • 或者shrink_slab会调用zs_shrink,zs_shrink会调用 zs_compact根据需要需要做清理。
  • 24.
  • 25.内部碎片问题的相关PATCH • 相关的PATCH主要集中在zsmalloc.c,集成难度不 大,建议内核不是很老的系统遇到相关问题可以打 上尝试一下。 • 另外注意在今年有一个关于handle写保护的修复务 必打上。
  • 26.外部碎片和 不可移动页面(见下图) • 因为一个设计引起的问题,所以放在一起介绍。 • 深度使用ZRAM后的现象: 1. 系统经常遇到连续页面分配失败的报错。 2. 系统可移动页块变少,不可移动页块变越来越 多。 3. 因为页面碎片增加引起的系统变慢。 4. 在打上各种主动使用CMA相关的PATCH后(具体 可见到2014年在CLK上关于CMA的演讲),ZRAM 中存放比较多内存后,还会遇到CMA页面剩下 很多,普通内存剩下很少的情况。
  • 27.外部碎片和不可移动页面的成因(见下图) • ZSMALLOC分配的页面为不可移动页面。 • 被放入ZRAM的LRU页面(可移动)变成不可移动页 面,这些页面不能被LINUX内核系统的除碎页功能处 理,导致系统页面碎片化严重。 • 导致了现象1,2,3。 • CMA页面不能被当成不可移动页面分配(原理同样见 我2014年在CLK的演讲),导致了现象4。 题外话:碎片问题在A64上被放大因为A64的THREAD_SIZE比A32大。 • 除ZSMALLOC外,去年到今年还有若干相关提高。 
  • 28.
  • 29.外部碎页解决方案:Non-LRU page migration (见下图) • 没有条件就创造条件,不能移动就让它能移动。 • 在ZSMALLOC内部,handle已经在前面处理好可以保 证obj迁移到其他页面,处理掉之前保存在page结构 里面的ZSMALLOC相关信息,实现了相关接口就令 ZSMALLOC中使用的页可迁移了。
  • 30.
  • 31.
  • 32.外部碎页问题的相关PATCH • 因为要对页面移动相关代码进行修改,涉及到不少 Linux内存管理相关代码,有一定难度。 • 依赖内部碎页的相关修正patch。
  • 33.问题都解决完了 再次查找彩蛋
  • 34.ZRAM的低压缩率问题 • 这是我看到的一个比较极端的例子,ZRAM中70%的页面起到的压缩作用是0。 • 实际情况可能没有这么糟糕,另外CONFIG_ZSMALLOC_STAT选择默认不打开,所以一般人 可以做到眼不见心不烦。 • 这样的PAGE浪费了CPU的时间,浪费了ZRAM空间。 • 这时勉强能起到的作用只有把非HIGHMEM ZONE的页面保存到HIGHMEM ZONE上,在一定 程度上节省了非HIGHMEM ZONE。 但是64位时代到来,使用HIGHMEM减少,优势不再明显。
  • 35.ZRAM的本质,提高思路的来源(见下图) • 用CPU和少量内存换取系统BLOCK IO和比较多数量内 存。 • 存放到ZRAM中的页面压缩率越好,ZRAM的工作效 果越好。 • 但是现在不能选择,只能照单全收。
  • 36.Android有SWAP
  • 37.
  • 38.Non-Swap(见下图) • 为了提高ZRAM压缩率。 • 其思路是把压缩率不高的页面不写入ZRAM,同时将 其从LRU列表中抽出去放到单独的页列表保证其不会 再次被写入ZRAM。 当这些页面再次被写时,表明其有可能在压缩率上 出现变化,将其再次放回LRU列表。
  • 39.Non-Swap的实现(见下图) • 根据设置放弃在ZRAM中存储压缩率不高的页。 • 具体步骤: shrink_page_list在发送PAGE到ZRAM之前把UNMAP PAGE改为把页面设置为只读。 把页面发给ZRAM。 ZRAM压缩页面,然后检查压缩率,压缩率不足的页面设置NON-SWAP标志。 返回shrink_page_list,把没有NON-SWAP也没有在发送到ZRAM过程中被写入的页面UNMAP然 后释放掉。 把被设置为NON-SWAP的页面丢入UNEVICTABLE列表防止再次被shrink_page_list。 一直到这个页面被写触发handle_pte_fault,在这里去掉NON-SWAP标志并踢回LRU PAGE列表。 •https://lkml.org/lkml/2016/8/22/151
  • 40.
  • 41.Non-Swap的效果(见下图) • 一个平台用内部稳定性测试。 未打上Non-Swap功能PATCH和打开Non-Swap功能后对比结果,每次 的LMK次数都降低50%以上。 最好的一次降低了79%。 能达到这点的原因我分析是因为当压缩率提高时,每做一组页面 shrink都可以获得比低压缩率更高的内存释放。 • 另外就是在考虑如何处理Non-Swap页面的时候,想到了如何让系 统支持任意多的watchpoint。 不过超过本话题讨论范畴了。
  • 42.
  • 43.谢谢!问题? weibo:@teawater_z 欢迎在线吐槽