图片无法显示,请右键点击新窗口打开图片

BiscuitOS 内存管理之分页大专题订阅入口

图片无法显示,请右键点击新窗口打开图片

在 Linux 中,文件是计算机存储数据的基本单元,它是计算机系统中用于存储、组织和管理信息的主要方式之一. 文件在 Linux 和其他操作系统中都扮演着重要的角色,文件用于存储各种类型的数据,包括文本、图像、音频、视频、程序代码等。文件是计算机上保存和检索信息的主要手段, 文件可用于组织和结构化数据。例如,文本文件可用于存储文档、配置文件和日志,而目录(文件夹)可用于组织文件和其他目录. 在硬件拓扑结构上,文件是存储在磁盘的,系统要访问文件需要经过以下步骤:

  • 应用程序请求: 流程的开始是由应用程序触发的,应用程序通过文件系统接口(如 open、read、write 等) 发起对文件的读写请求
  • 文件描述符: 当应用程序请求打开文件时,内核为该文件分配一个文件描述符。文件描述符是一个整数,用于标识打开的文件
  • 文件操作:
    • 读取文件: 当应用程序请求读取文件时,内核会检查文件是否在 Page Cache 中,如果在缓存中,则直接从缓存中返回数据。如果不在缓存中,则内核会从磁盘读取数据,并将数据复制到内存中,并可能将其放入 Page Cache 中以备将来使用
    • 写入文件: 当应用程序请求写入文件时,内核会将数据写入内存中的缓冲区。然后内核根据文件系统的策略将数据写入 Page Cache 中,并在适当的时候将数据刷新到磁盘上的文件中
  • 同步和缓存管理:
    • 同步(Sync): 对于写操作,内核通常会将数据写入 Page Cache中,并不立即写入磁盘,以提高性能。然而,应用程序可以通过调用 fsync 或 fdatasync 等函数来强制刷新 Page Cache 中的数据到磁盘,以确保数据持久性
    • Page Cache 管理: 内核会自动管理 Page Cache,根据内存压力和策略来选择哪些数据块保留在缓存中,哪些数据块被丢弃
  • 文件关闭: 当应用程序不再需要文件时,通常会使用 close 系统调用关闭文件描述符。这将释放相关的资源,并可能导致数据刷新到磁盘

图片无法显示,请右键点击新窗口打开图片

在 Linux 里,访问普通文件(Regular File) 的方式通常有: Buffered I/OFile-MappedDirect I/O 以及 DAX(Direct Access), 通常文件访问使用 Buffered I/O 方式,它通过使用缓冲区(buffer)来管理文件数据,通常在用户空间和内核之间进行数据传输, 并提供了 POSIX 接口(Read/Write/OPEN/CLOSE) 用于文件访问。Linux 根据不同的场景,也会使用其他方式进行文件访问,这些方式直接的差异如下:

  • Buffered I/O: Buffered I/O 使用缓冲区来管理文件数据,它是默认的文件 I/O 方式。数据首先从磁盘读取到内核的 Page Cache 中,然后从 Page Cache 复制到用户空间的缓冲区。类似地,在写入文件时,数据首先被写入用户空间的缓冲区,然后从缓冲区复制到内核的 Page Cache,并最终刷新到磁盘。Buffered I/O 通过缓存来优化磁盘 I/O 操作,减少磁盘访问次数,提高文件访问速度
  • Page Cache: Page Cache 是内核中的一个缓存机制,用于存储文件数据的页。它是 Buffered I/O 的一部分,用于缓存文件数据块以加速文件读取和写入操作。Page Cache 的数据存储在内存中,并在文件 I/O 操作期间自动加载和卸载. Page Cache 的主要作用是减少磁盘 I/O,提高文件访问性能。当应用程序请求读取文件时,内核首先检查 Page Cache 中是否已经有所需的数据,如果有,就直接从内存中返回数据,而不需要从磁盘读取
  • Direct I/O: Direct I/O 是一种绕过 Page Cache 的文件 I/O 方式。它不使用内核的 Page Cache 来缓存文件数据,而是直接在用户空间和磁盘之间传输数据。这意味着数据不会在内核中缓存,而是直接读取或写入磁盘. Direct I/O 可以提供更精确的 I/O 控制,避免了Page Cache 可能引入的不确定性。它通常用于需要高度可预测性的 I/O 操作,如数据库管理系统
  • DAX(Direct Access): DAX 是一种特殊的 Direct I/O,用于直接在用户空间和存储设备之间进行数据访问,绕过了操作系统的文件系统和 Page Cache。DAX 允许应用程序将数据直接映射到存储设备上,以实现低延迟、高性能的 I/O 操作. DAX 适用于需要极低延迟和高性能的应用程序,如高速数据库系统和大规模数据分析

图片无法显示,请右键点击新窗口打开图片

在 Linux 中,文件映射方式分配内存是一种通过将文件内容映射到进程的地址空间来分配内存的方法。这通常使用 mmap 系统调用实现,可以将文件的一部分或整个文件映射到进程的内存中,使得进程可以直接读取和写入文件内容,就好像它们在内存中一样。这与匿名映射有以下区别:

  • 源数据: 使用文件映射时,内存区域的内容来自磁盘上的文件。进程可以访问文件的内容,对文件所做的更改也会反映回文件; 匿名映射是一种不与文件相关的内存映射,它没有关联的文件内容。通常匿名映射用于进程之间共享数据或分配零初始化的内存块
  • 数据可持久性: 文件映射通过文件映射分配的内存区域是持久性的,即进程终止后,文件内容仍然存在于磁盘上。这使得文件映射适合需要持久性数据存储和共享的情况; 匿名映射分配的内存区域在进程终止后被释放,其内容不会保留在磁盘上。这适用于临时数据存储和进程间通信,但不保留数据
  • 文件描述符: 与文件映射关联的内存区域通常需要文件描述符,这样进程可以通过文件描述符来操作文件内容; 匿名映射不需要文件描述符,它通常用于分配内存块,而不是操作文件
  • 初始化: 文件映射通常不需要显式初始化,因为它们的内容来自文件; 匿名映射通常需要显式初始化,因为它们没有关联的文件内容,可以使用 mmap 标志中的 MAP_ANONYMOUS 来分配零初始化的内存

图片无法显示,请右键点击新窗口打开图片

在 Linux 里可以使用 mmap 系统调用分配文件映射的虚拟内存,mmap 提供了很多参数可以灵活设置文件映射内存属性,具体如下:

  • ARG0: MAP_VADDR 可以指定文件映射内存的虚拟地址,该值为 NULL 是代表分配一个随机的虚拟地址,当该值为指定值时代表从指定的地址分配虚拟内存,该地址可能已经被分配出去,使用时调用者需要确保虚拟地址被覆盖.
  • ARG1: MAP_SIZE 指明了需要分配文件映射内存的大小,长度为 PAGE_SIZE 的倍数,不能为 0.
  • ARG2: 指明了文件映射内存的访问权限,其值可以是这些标志的合集: PROT_READ(可读)、PROT_WRITE(可写)、PROT_EXEC(可执行) 和 PROT_NONE(不可访问)
  • ARG3: 指明映射类型,该字段可以选择 MAP_SHARED(共享映射) 和 MAP_PRIVATE(私有映射),当不能包含 MAP_ANONYMOUS 标志,否则变成匿名内存.
  • ARG4: 映射文件描述符,该这段必须是需要映射文件的描述符.
  • ARG5: 指明映射文件相对文件开头的偏移.

图片无法显示,请右键点击新窗口打开图片

在 Linux 里,文件映射(File-Mapped) 的数据架构如上图,用户进程使用文件映射将文件映射到进程地址空间之后,进程使用 VMA 描述映射之后的虚拟内存区域,不同的文件系统会为 VMA 提供相应的 vm_ops,另外 vm_file 指向映射的文件(struct file), 其又指向唯一的 STRUCT inode, 其 mapping 成员用于指向 STRUCT address_space, 该数据结构用于维护文件与 PAGE CACHE 和 VMA 的映射关系,其中 i_mmap 成员指向一颗区间树(RB-TREE), 该区间树维护了映射到该文件的 VMA. 另外 i_pages 指向 XARRAY 数组,该数组维护了文件映射的 PAGE CACHE,每个 PAGE CACHE 对应一个 STRUCT page 数据结构,STRUCT page 的 mapping 成员反过来指向 STRUCT address_space, 那么可以知道 PAGE CACHE 被哪些 VMA 映射,因此形成了一个闭环.

图片无法显示,请右键点击新窗口打开图片

Linux 支持多种文件系统,每个文件系统都会为其下创建的文件(Regular File)提供文件操作接口和文件映射虚拟内存操作接口,重点看一下与文件映射有关的接口,STRUCT file_operations 提供的 mmap 函数用于将该文件系统的文件映射到进程的地址空间,get_unmapped_area 接口用于将该文件系统映射到进程地址空间指定位置或者对齐方式. STRUCT vm_operation_struct 提供了该文件系统文件映射到虚拟内存区域之后,虚拟内存区域的操作接口,其中 fault 接口用于进程访问该虚拟内存发生缺页的处理方法, huge_fault 接口用于在支持文件大页映射的虚拟内存发生缺页时的处理方法.

图片无法显示,请右键点击新窗口打开图片

BiscuitOS 内存管理之分页大专题订阅入口

图片无法显示,请右键点击新窗口打开图片