一文读懂|zRAM 内存压缩机制

2023-10-08 18:12

本文主要是介绍一文读懂|zRAM 内存压缩机制,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

内存是计算机系统最重要的资源之一,当操作系统内存不足时,进程申请内存将会失败,从而导致其运行异常或者崩溃。

Linux 内核提供 swap 机制来解决内存不足的情况,其原理是:

当系统内存不足时,内核会将进程不常用的内存交换(写入)到磁盘中,然后将这些内存归还给系统,系统可以将这些内存继续分配给其他需要使用内存的进程。

通过 swap 机制,系统可以将内存分配给需求更迫切的进程。但由于 swap 机制需要进行 I/O 操作,所以一定程度上会影响系统性能。那么是否存在一种能够节省内存,而且对性能影响较少的机制呢?

在 Linux-3.14 引入了一种名为 zRAM 的技术,zRAM 的原理是:将进程不常用的内存压缩存储,从而达到节省内存的使用。如下图所示:

zRAM 机制建立在 swap 机制之上,swap 机制是将进程不常用的内存交换到磁盘中,而 zRAM 机制是将进程不常用的内存压缩存储在内存某个区域。所以 zRAM 机制并不会发生 I/O 操作,从而避免因 I/O 操作导致的性能下降。

zRAM原理

由于 zRAM 机制是建立在 swap 机制之上,而 swap 机制需要配置 文件系统 或 块设备 来完成的。所以 zRAM 虚拟一个块设备,当系统内存不足时,swap 机制将内存写入到这个虚拟的块设备中。也就是说,zRAM 机制本质上只是一个虚拟块设备。

zRAM 的原理如下图所示:

从上图可以看出,在开启了 zRAM 机制的情况下,当系统内存不足时,内核会进行如下操作:

  • 通过 swap 机制从系统中查找一些进程不常用的内存。
  • 将这些不常用的内存交换到 zRAM 块设备中,而 zRAM 块设备首先会对这些不常用的内存进行压缩,然后存储起来。
  • 把不常用的内存压缩存储到 zRAM 块设备后,swap 机制会把这些不常用的内存归还给内核。
  • 当进程访问到这些被交换到 zRAM 块设备的内存时,swap 机制将会通过 zRAM 块设备解压这些内存,并且重新建立与进程的地址映射关系。

启用zRAM

1. 创建 zRAM 块设备

要启用 zRAM,首先需要创建 zRAM 块设备。要创建 zRAM 块设备,可以使用以下命令:

modprobe zram num_devices=1

num_devices 参数可以指定创建 zRAM 块设备的个数,上面命令创建了一个 zRAM 块设备,可以通过路径 /dev/zram0 来访问这个块设备。

2. 设置 zRAM 块设备的大小

创建完 zRAM 块设备后,可以通过以下命令来设置其空间大小:

echo 512M > /sys/block/zram0/disksize

上面命令设置了 zram0 的大小为 512MB,也就是说, zram0 能够存储 512MB 压缩后的数据。

3. 压缩算法选择

zRAM 机制支持多种压缩算法,不同的压缩算法有不同的压缩比率和压缩速度,用户可以按照自身的需求来选择不同的压缩算法。

要更改 zRAM 的压缩算法,可以使用下面命令:

echo lzo > /sys/block/zram0/comp_algorithm

上面命令将 zRAM 的压缩算法更改为 lzo,我们也可以通过下面命令来查看内核支持哪些压缩算法:

cat /sys/block/zram0/comp_algorithm
lzo [lz4]

从上面命令的输出可知,内核支持 lzo 和 lz4 两种压缩算法。

4. 将 swap 交换设备设置为 zRAM

要将 swap 的交换设备设置为 zRAM 块设备,可以使用以下命令:

mkswap /dev/zram0

当执行完上面这条命令后,内核将会使用 zram0 作为 swap 的交换设备。

 资料直通车:Linux内核源码技术学习路线+视频教程内核源码

学习直通车:Linuxc/c++高级开发【直播公开课】

零声白金VIP体验卡:零声白金VIP体验卡(含基础架构/高性能存储/golang/QT/音视频/Linux内核)

zRAM实现

zRAM 块设备驱动的实现代码主要在 drivers/block/zram/zram_drv.c 文件中,下面我们主要围绕此文件进行分析。

本文并不会介绍块设备驱动的编写流程,只会分析 swap 机制在进行内存交换时,与 zRAM 块设备驱动的交互。

压缩内存

当系统内存不足时,内核将会触发 swap 机制。swap 机制首先会从系统中选择一些进程不常用内存,然后将这些不常用的内存交换到 zRAM 块设备中(使用 zRAM 块设备作为交换设备的情况下)。

当 swap 机制将不常用的内存交换到 zRAM 块设备时,会调用 zram_make_request() 函数处理请求。而 zram_make_request() 最终会通过调用 zram_bvec_write() 函数来压缩内存,调用链如下:

zram_make_request()-> __zram_make_request()-> zram_bvec_rw()-> zram_bvec_write()

我们来分析一下 zram_bvec_write() 函数的实现,其代码如下:

static int
zram_bvec_write(struct zram *zram, struct bio_vec *bvec, u32 index, int offset)
{...// 1. 获取需要进行压缩的内存page = bvec->bv_page;...user_mem = kmap_atomic(page);uncmem = user_mem;...// 2. 对内存进行压缩ret = zcomp_compress(zram->comp, zstrm, uncmem, &clen);...// 3. 获取压缩后的数据src = zstrm->buffer;...// 4. 申请一个内存块保存压缩后的数据handle = zs_malloc(meta->mem_pool, clen);...cmem = zs_map_object(meta->mem_pool, handle, ZS_MM_WO);// 5. 将压缩后的数据保存到新申请的内存块中memcpy(cmem, src, clen);...// 6. 将压缩后的数据登记到 zRAM 块设备的表格中meta->table[index].handle = handle;...return ret;
}

为了简化分析过程,我们对代码进行精简。从上面的代码可以看出,zRAM 机制对内存进行压缩的步骤如下:

  • 获取需要进行压缩的内存,需要进行压缩的内存由 swap 机制提供。
  • 通过 zcomp_compress() 函数对内存进行压缩,src 指针指向压缩后的内存地址。
  • 通过 zs_malloc() 和 zs_map_object() 函数申请一块新的内存块,大小为压缩后数据的大小。
  • 将压缩后的数据复制到新申请的内存块中。
  • 将压缩后的数据记录到 zRAM 块设备的表格中。

由于 zRAM 块设备是建立在内存中的虚拟块设备,所以其并没有真实块设备的特性。真实块设备会将存储空间划分成一个个块,而 zram_bvec_write() 函数的 index 参数就是数据块的编号。此参数有 swap 机制提供,所以 zRAM 块设备驱动通过 index 参数作为原始内存数据的编号。

一图胜千言:

zRAM驱动有个数据块表,用来记录原始内存数据对应的压缩数据,此表的索引就是数据块的编号。swap 机制会维护此表格的使用情况,如哪个块是空闲的,哪个块被占用等。

当内存页被压缩后,swap 机制将会把原来的内存页释放掉,并且把所有映射到此内存页的进程解除映射,细节可以参考 swap 机制相关的资料。

对内存进行解压缩的过程与压缩过程相反,有兴趣的同学可以自行阅读代码,这里就不进行分析了。

原文作者:Linux内核那些事

这篇关于一文读懂|zRAM 内存压缩机制的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/167114

相关文章

Redis实现高效内存管理的示例代码

《Redis实现高效内存管理的示例代码》Redis内存管理是其核心功能之一,为了高效地利用内存,Redis采用了多种技术和策略,如优化的数据结构、内存分配策略、内存回收、数据压缩等,下面就来详细的介绍... 目录1. 内存分配策略jemalloc 的使用2. 数据压缩和编码ziplist示例代码3. 优化的

深入解析C++ 中std::map内存管理

《深入解析C++中std::map内存管理》文章详解C++std::map内存管理,指出clear()仅删除元素可能不释放底层内存,建议用swap()与空map交换以彻底释放,针对指针类型需手动de... 目录1️、基本清空std::map2️、使用 swap 彻底释放内存3️、map 中存储指针类型的对象

Python内存优化的实战技巧分享

《Python内存优化的实战技巧分享》Python作为一门解释型语言,虽然在开发效率上有着显著优势,但在执行效率方面往往被诟病,然而,通过合理的内存优化策略,我们可以让Python程序的运行速度提升3... 目录前言python内存管理机制引用计数机制垃圾回收机制内存泄漏的常见原因1. 循环引用2. 全局变

基于Redis自动过期的流处理暂停机制

《基于Redis自动过期的流处理暂停机制》基于Redis自动过期的流处理暂停机制是一种高效、可靠且易于实现的解决方案,防止延时过大的数据影响实时处理自动恢复处理,以避免积压的数据影响实时性,下面就来详... 目录核心思路代码实现1. 初始化Redis连接和键前缀2. 接收数据时检查暂停状态3. 检测到延时过

Redis中哨兵机制和集群的区别及说明

《Redis中哨兵机制和集群的区别及说明》Redis哨兵通过主从复制实现高可用,适用于中小规模数据;集群采用分布式分片,支持动态扩展,适合大规模数据,哨兵管理简单但扩展性弱,集群性能更强但架构复杂,根... 目录一、架构设计与节点角色1. 哨兵机制(Sentinel)2. 集群(Cluster)二、数据分片

一文带你迅速搞懂路由器/交换机/光猫三者概念区别

《一文带你迅速搞懂路由器/交换机/光猫三者概念区别》讨论网络设备时,常提及路由器、交换机及光猫等词汇,日常生活、工作中,这些设备至关重要,居家上网、企业内部沟通乃至互联网冲浪皆无法脱离其影响力,本文将... 当谈论网络设备时,我们常常会听到路由器、交换机和光猫这几个名词。它们是构建现代网络基础设施的关键组成

深入理解go中interface机制

《深入理解go中interface机制》本文主要介绍了深入理解go中interface机制,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学... 目录前言interface使用类型判断总结前言go的interface是一组method的集合,不

C# async await 异步编程实现机制详解

《C#asyncawait异步编程实现机制详解》async/await是C#5.0引入的语法糖,它基于**状态机(StateMachine)**模式实现,将异步方法转换为编译器生成的状态机类,本... 目录一、async/await 异步编程实现机制1.1 核心概念1.2 编译器转换过程1.3 关键组件解析

Java使用Thumbnailator库实现图片处理与压缩功能

《Java使用Thumbnailator库实现图片处理与压缩功能》Thumbnailator是高性能Java图像处理库,支持缩放、旋转、水印添加、裁剪及格式转换,提供易用API和性能优化,适合Web应... 目录1. 图片处理库Thumbnailator介绍2. 基本和指定大小图片缩放功能2.1 图片缩放的

Redis客户端连接机制的实现方案

《Redis客户端连接机制的实现方案》本文主要介绍了Redis客户端连接机制的实现方案,包括事件驱动模型、非阻塞I/O处理、连接池应用及配置优化,具有一定的参考价值,感兴趣的可以了解一下... 目录1. Redis连接模型概述2. 连接建立过程详解2.1 连php接初始化流程2.2 关键配置参数3. 最大连