一、内存压缩技术体系概览

在现代服务器中,内存资源是最贵重的分配对象之一。Linux内核提供了复杂的内存管理子系统,聚焦于在有限物理内存下为多用户提供高效、可控的分配与回收,同时配合磁盘swap等排量机制实现内存超划。Linux内核的内存管理是一个很大的课题,本文聚焦于特别重要的几个方面:zswap压缩交换(compressed swap cache)、zram内存磁盘(compressed RAM disk)、以及LRU页面回收算法与kswapd合并构接的全链路协同。

Linux的内存压缩体系在传统swap和物理内存之间构建了多层缓冲,核心目标是减少磁盘I/O延迟。当物理内存紧张时,内核需要将不活跃的页面驱逐到磁盘(swap),但这会导致严重的性能下降。通过在内存中维护压缩缓存层,可以大幅减少实际落盘的页面数量,从而提升系统在内存压力下的响应速度。

二、物理页面(Page)与内存映射基础

struct page是内存管理的基本单位。每个物理页面对应一个struct page构价,保存标志、计数、链表等控制信息。内核通过一个内存模型约束(ASMS),且在主流平台上使用flatmem模型,即物理内存物理地址连续。与PAGE_SIZE=4096字节相关联的是,内核通过一个全局数组——mem_map,来定位所有页面的struct page实例。

struct page中关键的flags位包括:

  • PG_lru:表示该页面在LRU链表上,参与页面回收
  • PG_referenced:表示页面最近被访问过,用于二次机会算法
  • PG_swapbacked:表示该页面可以被swap到磁盘
  • PG_slab:表示该页面由SLAB分配器管理
  • PG_workingset:标识工作集页面,避免被过早回收

物理页面按照zone分区组织:ZONE_DMA(0-16MB,用于老式DMA控制器)、ZONE_NORMAL(直接映射区,内核线性映射)、ZONE_HIGHMEM(仅在32位系统中需要)。64位系统中,ZONE_HIGHMEM通常不存在,全部物理内存直接映射到内核地址空间。

三、zswap压缩交换池(Compressed Swap Cache)

1. 基本设计理念

zswap是一种转换层(entry store manager),即当会释放页面为swap space时,会先将页面数据压缩后存储在一个内存中的特殊对象池。当内核需要释放更多内存空间时,可直接释放压缩池中的对象,而不需要用旧的压缩数据存储在磁盘swap区。快速回入(FAST), 当需要再次访问该页面时,直接从压缩池中解压恢复,无需磁盘I/O。

2003年提出的swap cache基本思想,即在磁盘swap之外,以内存中可用余额作为现值紧密冲突的buffer,特别是在swap低于物理内存时将内存借给磁盘发生的用户需求,用于扩展叠加。

2. 核心数据结构

zswap核心结构包括:

  • struct zswap_pool:对应一个压缩合并池,包含内核余额信息、压缩工具框架、的列表(用于预测未来的叠加),以及该池支持的工作数。
  • struct zswap_entry:页面的压缩对象,带有被压缩的数据、对应的swap 插种,以及指向元数据。
  • struct zswap_tree:用于教师的数据结构,红黑树(Red-Black Tree)促进有效定位。

3. 压缩算法选择

zswap通过zswap.compressor开关对外,内核支持同时加载多个compressor模块(modprobe lz4hc zstd zstd_comp),同时仅有一个池使用指定compressor,其他框架用来设定中的一臂,实际上,当放大和压缩时,同时使用1为基本,1个有限联营

常用压缩算法对比:

  • LZ4:压缩速率极快(数百MB/s),压缩比低(1.5-2x),适合延迟敏感场景
  • LZ4HC:LZ4高压缩版本,压缩比提升明显但速度略降
  • zstd:压缩比高(2.8-3.5x),压缩/解压速度均衡,目前推荐默认算法
  • deflate(zlib):Linux传统算法,压缩比中等但速度较慢,已不推荐
  • 842:硬件加速友好的轻量级算法,压缩比约1.7x

4. Squeeze(叠加)优化

zswap 的内存来源是通过zsmalloc分配器,利用zsmalloc pool,将多个小对象抓取一起压缩合并存储在一块物理页内,这是因为一个zswap对象有时肯定小于全页,如果组件自己接对一个内存页可以比较流程,效率很低,这种叠加(squeeze d)的想法受到UNIX工作在0工作中的启发,实现50-70%的额外内存利用率提升。这种体制当物理内存已经用尽,可以直接将小对象穿梭口利用这些空间,而无需再把冲突陈旧数据重新写回磁盘。

5. 与普通swap的区别

zswap是左右隔离的同情说,它与有限swap区的大小无关,极限同一为一层。zswap自己不接方swap allocator,而仅作为一个callback压缩呼吸联心。zswap的swap_in_d(store and a swap)和swap_d_out(map into guest memory from compressed cache,释放 = 函数),将压缩数据传输到zswap pool | zswap 将压缩数据停口。

zswap的关键参数:

  • /sys/module/zswap/parameters/enabled:总开关(Y/N)
  • /sys/module/zswap/parameters/compressor:当前压缩算法
  • /sys/module/zswap/parameters/zpool:当前内存分配池(zbud/zsmalloc)
  • /sys/module/zswap/parameters/max_pool_percent:压缩池最大占物理内存百分比(默认20%)

zswap提供的统计信息在/sys/kernel/debug/zswap/目录下可见:

  • pool_total_size:压缩池当前占用的物理内存字节数
  • stored_pages:当前存储的压缩页面数量
  • pool_limit_hit:压缩池达到上限的次数
  • reject_compress_poor:因压缩效果差被拒绝的次数
  • reject_kmsalloc_fail:因内存分配失败被拒绝的次数

四、zram内存磁盘(Compressed RAM Disk)

1. 设计理念

zram比zram更有转换,它创建一个存储在内存中的压缩块设备,并使用这个压缩块设备作为一个swap区(swap area)。zram无需额外磁盘空间,全部由内存使用,特别适用于无磁盘的手机、相机、IoT设备。

Linux内核v4.14之后,zram支持多压缩流和写回(writeback)机制——可以将压缩池中真正不活跃的旧数据写回磁盘存储,从而释放压缩池空间。

2. 核心数据结构 struct zram:

  • struct lz4_ctx / zstd_ctx等:压缩/解压缩工作的私有上下文
  • table:哈希映射表,加速元数据查找
  • mem_pool:内存池,存放压缩后的数据
  • comp stream / req:压缩请求队列
  • max_comp_streams:最大支持的并行压缩流数
  • max_writeback_limit:写回操作的总大小限制

每个zram设备使用/dev/zramN接口。常用的工具链:

  • mkswap /dev/zram0:格式化为swap设备
  • swapon /dev/zram0 -p 100:启用zram swap区,优先级高于磁盘swap
  • cat /sys/block/zram0/mm_stat:查看统计信息(原始大小、压缩后大小、元数据大小)
  • cat /sys/block/zram0/comp_algorithm:查看/设置压缩算法
  • cat /sys/block/zram0/idle:查看写回机制的Idle页面数
  • cat /sys/block/zram0/writeback:启用写回机制

3. zswap vs zram 对比总结:

  • 架构层面:zswap是swap层的缓存(entry store),zram是块设备层(block device)
  • 内存来源:zswap的压缩池内存来源于页面回收释放的页面;zram的内存来源于预分配的压缩缓冲区
  • 生态系统:zswap无用户态工具,纯内核参数控制;zram可通过zramctl工具精细管理
  • 使用率:zswap常用于服务器场景(与磁盘swap配合);zram常用于桌面/移动设备(替代磁盘swap)
  • 写回支持:zswap不支持写回磁盘;v4.14+ zram支持writeback到后端磁盘

五、LRU算法与页面回收

1. LRU核心思想

LRU(Least Recently Used,最近最少使用)是操作系统中最经典的缓存淘汰算法之一。Linux内核中的LRU实现远比教科书上的简单版本复杂得多——因为内核需要处理多种页面类型(匿名页、文件映射页、共享内存页等),并且需要在多核处理器上高效运行(减少锁竞争)。

2. LRU四种类型及其含义

  • Active Anon:活跃匿名页——应用程序的动态分配内存(堆、栈),最近被CPU访问过
  • Inactive Anon:非活跃匿名页——最近未访问的匿名页,首选被回收(swap)
  • Active File:活跃文件映射页——文件内容被映射到进程地址空间且最近被访问
  • Inactive File:非活跃文件映射页——最近未访问的文件映射页,首选被丢弃(因为原数据在磁盘上)
  • SUnreclaim (Shmem/Unreclaimable):不可回收页面——共享内存、内核锁定内存、内存映射设备等

3. LRU双链表机制

内核维护两个全局链表:Active链表和Inactive链表。新页面首次访问时进入Inactive链表,如果再次被访问(PG_referenced位置1),则晋升到Active链表。如果Active链表页面经过一段时间未被访问,则降级回Inactive链表。需要回收时,从Inactive链表尾部取出页面进行回收。

具体流程(shrink_lruvec函数):

  1. get_scan_count():根据优先级和内存扫描比例,计算每个链表需要扫描的页面数
  2. shrink_list():遍历链表中的页面,检查PG_referenced标志:若已设置,清除标志并将页面移到Active链表;若未清除,加入回收候选集
  3. shrink_page_list():将候选页面分为立即回收(跳过活性页面)和稍后处理
  4. shrink_anon() + shrink_anon_page():对匿名页执行swap
  5. shrink_page_list()中的__remove_mapping():从页缓存/swap cache中移除映射

4. Multi-Gen LRU (mGLRU)

Yu等人的痛点是内核swap当大li,将在内存压力下先的,不再通过测试页面访问来提升效率,而是创建多个不双的生(generations,旵之卡于双链表的 —— —— —— — 2.1 上的动态测试,而是囚下的 clear_idx,利用建与方的质换ᐦ— —— —— — 2.1 上规规测试棟,内提工作集合布。

mGLRU的核心创新:

  • 不再依赖PG_referenced位,而是通过生成时间和访问模式自动识别活跃/非活跃
  • 支持多代内存管理(一般4-8代),不同工作集大小获得更合适的扫描频率
  • 扫描开销低,理论上仅页表遍历(不需要修改page结构)
  • 5.15内核引入,6.x内核持续优化

六、kswapd内核线程与回收方式

1. 痛点

一个压脱的high-tension小组,内核kswapd小组/thread的小组,同时scene同时wakeup_kswapd小组通过Balance-唤醒。kswapd是每个zone(node)的独立守护线程,在后台持续监控内存使用率。当内存使用率低于high watermark时休眠;当内存出现压力(到达low watermark)时唤醒执行回收。

2. 回收优先级

kswapd三层回收优先级(kc):

  • alloc_priority = 12 → 10(异步回收):关注回收Active/Inactive链表中的非必要页面,不阻塞分配请求
  • alloc_priority = 9 → 5(同步回收):使用wait_page_idle等机制延迟回收,短暂阻塞
  • alloc_priority = 4 → 1(激进回收):直接回收(direct reclaim),完全阻塞分配请求直到回收完成

3. direct reclaim 与 kswapd 的配合

当direct reclaim无法满足严重内存压力(min watermark以下),内核会触发OOM killer。OOM killer通过select_bad_process()基于OOM score选择分数最高的进程终止释放内存,通过oom_kill_process()实现。这对生产环境是灾难性的,因此需要合理设置/proc/sys/vm/overcommit_memory、OOMScoreAdjust等参数。

4. page compaction 碎片整理

当物理页面碎片化严重时,大页内存分配(如THP、HugeTLB)会失败。kernel中内置的kcompactd线程负责检测物理碎片率并执行页面移动整理。关键参数:/proc/sys/vm/compact_memory、/sys/kernel/debug/extfrag/extfrag_threshold。

七、实战:内存压缩技术配置与调优

场景一:桌面/笔记本 + 8GB RAM + SSD

推荐配置zram + 少量磁盘swap组合:

# 启用zram
modprobe zram
echo lz4 > /sys/block/zram0/comp_algorithm
echo 4G > /sys/block/zram0/disksize
mkswap /dev/zram0
swapon /dev/zram0 -p 50

# 仍然保留磁盘swap作为fallback
swapon /swapfile -p 10

# 减少swap倾向度(保持更多活跃页面在内存中)
sysctl vm.swappiness=10

场景二:云服务器 + 16GB RAM + 高性能SSD

推荐配置zswap + 磁盘swap:

# 启用zswap
echo Y > /sys/module/zswap/parameters/enabled
echo zstd > /sys/module/zswap/parameters/compressor
echo zsmalloc > /sys/module/zswap/parameters/zpool
echo 25 > /sys/module/zswap/parameters/max_pool_percent

# 启用磁盘swap
swapon /swap

# 平衡设置
sysctl vm.swappiness=60

场景三:嵌入式设备 + 512MB RAM + 无磁盘

推荐配置zram作为唯一swap:

# 启用zram-only swap
modprobe zram
echo lz4 > /sys/block/zram0/comp_algorithm
echo 256M > /sys/block/zram0/disksize
mkswap /dev/zram0
swapon /dev/zram0 -p 32767

# 极度减少swap倾向,以防止OOM
sysctl vm.swappiness=180

八、内存压缩:观测与调试工具

1. /proc 与 /sys 接口

  • /proc/meminfo:SwapTotal(总swap容量)、SwapFree(空闲swap)、Compressed(仅zswap的压缩内存字节数)、AnonPages(匿名页总数)
  • /proc/vmstat:pswpin/pswpout(swap in/out 页面数)、pgpgin/pgpgout(页面level I/O)、oom_kill(OOM次数)
  • /sys/kernel/debug/zswap/:zswap专属统计
  • /sys/block/zram0/mm_stat:zram压缩比等详细统计
  • /sys/block/zram0/:zram控制参数

2. perf 与 eBPF 观测

使用perf stat -e dTLB-loads,dTLB-load-misses统计dTLB Miss率,间接反映页面活动频繁度;通过eBPF程序funclatency -u shrink_lruvec分析回收函数的执行时间,找出性能瓶颈。

3. numastat 与 NUMA平衡

在NUMA多核服务器上,内存压缩需要考虑NUMA拓扑。numactl --interleave=all可以提高zswap的利用率;numastat -z pid查看进程的内存绑定情况。

4. vmstat 实时诊断

vmstat 1输出的bi/bo字段判断swap活动是否频繁;si/so字段直接反映swap I/O;free/buff/cached列判断内存使用结构是否健康。

九、常见问题与最佳实践

问题1:zswap效果不明显,压缩池频繁满

原因:压缩池最大值太低(max_pool_percent默认仅20%)。解决方法:适当提升到30-40%,但也不要过高影响应用可用内存。对于数据密集工作负载(压缩比低),考虑压缩算法选择(zstd比lz4产生更高压缩比)。

问题2:频繁OOM

原因:进程真正耗尽了所有可用内存,或swap机制配置不当(swappiness过高触发过早回收)。解决方法:检查dmesg | grep oom-killer找出被杀进程,优化应用内存使用或使用memory.limit_in_bytes(cgroup)硬性限制。

问题3:磁盘I/O突然飙升

原因:直接回收(direct reclaim)频繁触发大量压缩后页面落盘。解决方法:设置min_free_kbytes预留更多紧急内存缓冲,避免进入直接回收;调整vfs_cache_pressure降低文件缓存回收频率。

最佳实践总结:

  • 服务器场景优先zswap(减少磁盘swap活动,利用内存中的压缩缓存)
  • 桌面/移动场景优先zram(不依赖磁盘swap,响应灵敏)
  • 压缩算法:zstd > lz4hc > lz4(性能/压缩比平衡)
  • zswap压缩池大小设置为物理内存的20-30%
  • vm.swappiness依据负载调整(计算密集型低,I/O密集适中)
  • 监控/proc/vmstat中的pswpin/pswpout趋势,I/O持续增加说明内存压力大

十、总结

Linux内核的内存压缩技术体系从磁盘swap演进到压缩交换池(zswap)、内存磁盘(zram),为不同场景提供了灵活高效的解决方案。理解zswap的entry store架构、zram的块设备压缩机制、LRU双链表与mGLRU的演化、kswapd与direct reclaim的配合,是从根本上掌握Linux内存管理的关键。

在实战生产环境中,应根据硬件配置(RAM大小、磁盘类型)和业务特征(计算密集vs内存密集)选择合适的内存压缩策略。通过正确配置压缩算法、合理设置swappiness参数、持续监控vmstat/mm_stat等统计信息,可以在最大化内存利用率的同时确保服务稳定性。

随着mGLRU在Linux 5.15+中的成熟、zstd压缩算法的普及、以及zram writeback机制的完善,Linux内核的内存压缩能力将继续提升,为云原生、容器化、边缘计算等新兴场景提供坚实的内存管理基础。

点赞(0) 打赏

评论列表 共有 0 条评论

暂无评论
立即
投稿

微信公众账号

微信扫一扫加关注

发表
评论
返回
顶部