Linux内核黑科技——mmap实现详解

article/2025/10/23 10:26:36
前言:故事的开始是这样的,某天在脉脉上看到有人发了下面的帖子:

想不到 mmap 都成了黑科技了,为了让大家都能了解这个黑科技,所以还是写篇文章来详细介绍一下 mmap 的实现吧。

其实,源码分析是比较难写的,主要有两个原因:

  • 一方面是源码实现一般会涉及多个知识点,所以在分析源码时需要穿插多个知识点,从而增加分析的难度。
  • 另一方面是源码实现会处理很多细节问题,这些细节问题虽然不是设计的主要框架,但忽略了有时会让人摸不着头脑。

所以,为了降低分析的难度和让读者能够更容易看懂,在分析源码时更注重知识点的实现,而在不影响理解的情况下,我会忽略一些细节问题。而对于穿插其他知识点的时候,会先跳过其实现,并且在后续的文章对其进行分析。

mmap 原理

mmap 的全称是 memory map,中文意思是 内存映射。其用途是将文件映射到内存中,然后可以通过对映射区的内存进行读写操作,其效果等同于对文件进行读写操作。

下面我们通过一幅图来对 mmap 的原理进行阐述:

从上图可以看出,mmap 的原理就是将虚拟内存空间映射到文件的页缓存,我们可以知道:对文件进行读写时需要经过页缓存进行中转的。所以当虚拟内存地址映射到文件的页缓存后,就可以直接通过读写映射区内存来对文件进行读写操作。

mmap 实现

1. 文件映射

当我们使用 mmap() 系统调用对文件进行映射时,将会触发调用 do_mmap_pgoff() 内核函数来完成工作,我们来看看 do_mmap_pgoff() 函数的实现(经过精简后):

unsigned long
do_mmap_pgoff(struct file *file, unsigned long addr, unsigned long len, unsigned long prot, unsigned long flags, unsigned long pgoff)
{...// 1. 获取一个未被使用的虚拟内存区addr = get_unmapped_area(file, addr, len, pgoff, flags);if (addr & ~PAGE_MASK)return addr;...// 2. 调用 mmap_region() 函数继续进行映射操作return mmap_region(file, addr, len, flags, vm_flags, pgoff, accountable);
}

经过精简后的 do_mmap_pgoff() 函数主要完成 2 个工作:

  • 首先,调用 get_unmapped_area() 函数来获取进程没被使用的虚拟内存区,并且返回此内存区的首地址。
  • 然后,调用 mmap_region() 函数继续进行映射操作。
在 32 位的操作系统中,每个进程都有 4GB 的虚拟内存空间,应用程序在使用内存前,需要先向操作系统发起申请内存的操作。操作系统会从进程的虚拟内存空间中查找未被使用的内存地址,并且返回给应用程序。
操作系统会记录进程正在使用中的虚拟内存地址,如果内存地址没被登记,说明此内存地址是空闲的(未被使用)。

我们继续来看看 mmap_region() 函数的实现,代码如下(经过精简后):

unsigned long
mmap_region(struct file *file, unsigned long addr,unsigned long len, unsigned long flags,unsigned int vm_flags, unsigned long pgoff,int accountable)
{struct mm_struct *mm = current->mm;struct vm_area_struct *vma, *prev;int correct_wcount = 0;int error;...// 1. 申请一个虚拟内存区管理结构(vma)vma = kmem_cache_zalloc(vm_area_cachep, GFP_KERNEL);...// 2. 设置vma结构各个字段的值vma->vm_mm = mm;vma->vm_start = addr;vma->vm_end = addr + len;vma->vm_flags = vm_flags;vma->vm_page_prot = protection_map[vm_flags & (VM_READ|VM_WRITE|VM_EXEC|VM_SHARED)];vma->vm_pgoff = pgoff;if (file) {...vma->vm_file = file;/* 3. 此处是内存映射的关键点,调用文件对象的 mmap() 回调函数来设置vma结构的 fault() 回调函数。*    vma对象的 fault() 回调函数的作用是:*        - 当访问的虚拟内存没有映射到物理内存时,*        - 将会调用 fault() 回调函数对虚拟内存地址映射到物理内存地址。*/error = file->f_op->mmap(file, vma);...}...// 4. 把 vma 结构连接到进程虚拟内存区的链表和红黑树中。vma_link(mm, vma, prev, rb_link, rb_parent);...return addr;
}

mmap_region() 函数主要完成以下 4 件事情:

  • 申请一个 vm_area_struct 结构(vma),内核使用 vma 来管理进程的虚拟内存地址
  • 设置 vma 结构各个字段的值。
  • 通过调用文件对象的 mmap() 回调函数来设置vma结构的 fault() 回调函数,一般文件对象的 mmap() 回调函数为:generic_file_mmap()
  • 把新创建的 vma 结构连接到进程的虚拟内存区链表和红黑树中。

内核使用 vm_area_struct 结构来管理进程的虚拟内存地址。当进程需要使用内存时,首先要向操作系统进行申请,操作系统会使用 vm_area_struct 结构来记录被分配出去的内存区的大小、起始地址和权限等。

我们来看看 vm_area_struct 结构的定义:

struct vm_area_struct {struct mm_struct *vm_mm;unsigned long vm_start;              // 内存区的开始地址unsigned long vm_end;                // 内存区的结束地址struct vm_area_struct *vm_next;      // 把进程所有已分配的内存区链接起来pgprot_t vm_page_prot;               // 内存区的权限...struct rb_node vm_rb;                // 为了加快查找内存区而建立的红黑树...struct vm_operations_struct *vm_ops; // 内存区的操作回调函数集unsigned long vm_pgoff;struct file *vm_file;                // 如果映射到文件,将指向映射的文件对象...
};struct vm_operations_struct {// 当虚拟内存区没有映射到物理内存地址时,将会触发缺页异常,// 而在缺页异常处理函数中,将会调用此回调函数来对虚拟内存映射到物理内存。int (*fault)(struct vm_area_struct *vma, struct vm_fault *vmf);...
};

当把文件映射到虚拟内存空间时,需要把 vma 结构的 vm_file 字段设置为要映射的文件对象,然后调用文件对象的 mmap() 回调函数来设置 vma 结构的 fault() 回调函数。

vma 结构的  fault() 回调函数的作用是:当虚拟内存区没有映射到物理内存地址时,将会触发缺页异常。而在缺页异常处理中,将会调用此回调函数来对虚拟内存映射到物理内存。

我们来看看 generic_file_mmap() 函数是怎么设置 vma 结构的 fault() 回调函数的:

struct vm_operations_struct generic_file_vm_ops = {.fault = filemap_fault, // 将 fault() 回调函数设置为:filemap_fault()
};int generic_file_mmap(struct file *file, struct vm_area_struct *vma)
{...vma->vm_ops = &generic_file_vm_ops;...return 0;
}

至此,文件映射的过程已经分析完毕。我们来看看其调用链:

sys_mmap()
└→ do_mmap_pgoff()└→ mmap_region()└→ generic_file_mmap()

2. 缺页异常

前面介绍了 mmap() 系统调用的处理过程,可以发现 mmap() 只是将 vma 的 vm_file 字段设置为被映射的文件对象,并且将 vma 的 fault() 回调函数设置为 filemap_fault()。也就是说,mmap() 系统调用并没有对虚拟内存进行任何的映射操作。

虚拟内存必须映射到物理内存才能使用。如果访问没有映射到物理内存的虚拟内存地址,CPU 将会触发缺页异常。也就是说,虚拟内存并不能直接映射到磁盘中的文件。

那么 mmap() 是怎么将文件映射到虚拟内存中呢?

读写文件时并不是直接对磁盘上的文件进行操作的,而是通过 页缓存 作为中转的,而页缓存就是物理内存中的内存页。所以,mmap() 可以通过将文件的页缓存映射到虚拟内存空间来实现对文件的映射。

但我们在 mmap() 系统调用的实现中,也没看到将文件页缓存映射到虚拟内存空间。那么映射过程是在什么时候发生的呢?

答案就是: 缺页异常

由于 mmap() 系统调用并没有直接将文件的页缓存映射到虚拟内存中,所以当访问到没有映射的虚拟内存地址时,将会触发 缺页异常。当 CPU 触发缺页异常时,将会调用 do_page_fault() 函数来修复触发异常的虚拟内存地址。

我们主要来看看 do_page_fault() 函数对文件映射的实现部分,其调用链如下:

do_page_fault()
└→ handle_mm_fault()└→ handle_pte_fault()└→ do_linear_fault()└→ __do_fault()

所以我们直接来看看 __do_fault() 函数的实现:

static int
__do_fault(struct mm_struct *mm, struct vm_area_struct *vma,unsigned long address, pmd_t *pmd, pgoff_t pgoff,unsigned int flags, pte_t orig_pte)
{...vmf.virtual_address = address & PAGE_MASK; // 要映射的虚拟内存地址vmf.pgoff = pgoff;                         // 映射到文件的偏移量vmf.flags = flags;                         // 标志位vmf.page = NULL;                           // 映射到虚拟内存中的物理内存页// 1. 如果虚拟内存管理区提供了 falut() 回调函数,那么将调用此函数来获取要映射的物理内存页,//    我们在 mmap() 系统调用的实现中看到,已经将其设置为 filemap_fault() 函数了。if (likely(vma->vm_ops->fault)) {ret = vma->vm_ops->fault(vma, &vmf);...}...if (likely(pte_same(*page_table, orig_pte))) {...// 2. 通过物理内存页生成一个页表项值(可以参考内存映射一文)entry = mk_pte(page, vma->vm_page_prot);if (flags & FAULT_FLAG_WRITE)entry = maybe_mkwrite(pte_mkdirty(entry), vma);// 3. 将虚拟内存地址映射到物理内存(也就是将进程的页表项设置为刚生成的页表项的值)set_pte_at(mm, address, page_table, entry);...}...return ret;
}

__do_fault() 函数对处理文件映射部分主要分为 3 个步骤:

  • 调用虚拟内存管理区结构(vma)的 fault() 回调函数(也就是 filemap_fault() 函数)来获取到文件的页缓存。
  • 将虚拟内存地址映射到页缓存的物理内存页(也就是将进程的页表项设置为上面生成的页表项的值)。

对于 filemap_fault() 函数是怎样读取文件页缓存的,本文不作解释,有兴趣的可以自行阅读源码。

最后,我们以一幅图来描述一下虚拟内存是如何与文件进行映射的:

从上图可以看出,mmap() 是通过将虚拟内存地址映射到文件的页缓存来实现的。当对映射后的虚拟内存进行读写操作时,其效果等价于直接对文件的页缓存进行读写操作。对文件的页缓存进行读写操作,也等价于对文件进行读写操作。

 

 


http://chatgpt.dhexx.cn/article/hoq4E7aE.shtml

相关文章

【Linux】Linux编程之 mmap解析

前言 虚拟内存系统通过将虚拟内存分割为称作虚拟页(Virtual Page,VP)大小固定的块,一般情况下,每个虚拟页的大小默认是4096字节。同样的,物理内存也被分割为物理页(Physical Page,PP),也为4096字节。 一、…

讲一讲什么是 MMAP

1. mmap 基础概念 mmap 即 memory map,也就是内存映射。 mmap 是一种内存映射文件的方法,即将一个文件或者其它对象映射到进程的地址空间,实现文件磁盘地址和进程虚拟地址空间中一段虚拟地址的一一对映关系。实现这样的映射关系后&#xff…

人工神经网络的应用有哪些方面,人工神经网络在生活中的应用

人工神经网络的应用 人工神经网络(Artificial Neural Network,简称ANN ),以数学模型模拟神经元活动,是基于模仿大脑神经网络结构和功能而建立的一种信息处理系统。人工神经网络具有自学习、自组织、自适应以及很强的非…

人工神经网络有哪些算法,神经网络都有哪些算法

人工神经网络分类方法 从20世纪80年代末期,人工神经网络方法开始应用于遥感图像的自动分类。 目前,在遥感图像的自动分类方面,应用和研究比较多的人工神经网络方法主要有以下几种:(1)BP(BackP…

深度学习-人工神经网络概述

人工神经网络 简述 很多术语听起来很唬人,“人工神经网络”就属于其中之一。在很多人看来,我们对人类的神经系统还没有研究透彻,这就来了一个“人工的”神经网络,人脑这样复杂,那么人工神经网络一定相当高深莫测。如果…

人工神经网络的应用实例,人工神经网络实际应用

神经网络算法实例说明有哪些? 在网络模型与算法研究的基础上,利用人工神经网络组成实际的应用系统,例如,完成某种信号处理或模式识别的功能、构作专家系统、制成机器人、复杂系统控制等等。 纵观当代新兴科学技术的发展历史&…

人工神经网络算法实战教程

神经网络(Artificial Neural Network,也称为人工神经网络,简称ANN)具有通过示例学习能力。ANN是受生物神经元系统启发的的信息处理模型,它由大量高度互联的处理元素组成,这些处理元素被称神经元&#xff0c…

人工神经网络的三个要素,神经网络三要素是指

一个完整的人工神经网络包括 人工神经网络主要架构是由神经元、层和网络三个部分组成。整个人工神经网络包含一系列基本的神经元、通过权重相互连接。神经元是人工神经网络最基本的单元。 单元以层的方式组,每一层的每个神经元和前一层、后-层的神经元连接&#x…

人工神经网络连接方式,全连接神经网络作用

人工神经元网络的拓扑结构主要有哪几种?谢谢大侠~~~ 神经网络的拓扑结构包括网络层数、各层神经元数量以及各神经元之间相互连接的方式。人工神经网络的模型从其拓扑结构角度去看,可分为层次型和互连型。 层次型模型是将神经网络分为输入层&#xff08…

神经网络算法的具体流程,人工神经网络算法步骤

神经网络 算法 思路?能否提供一个最简单的代码? 30 。 最基本的BP算法:1)正向传播:输入样本->输入层->各隐层(处理)->输出层注1:若输出…

人工神经网络的基本原理

1.1 人工神经网络原理 MeCulloch 和 Pitts 基于对大脑神经元的研究提 出了人工神经元模型(M-P 模型)。人工神经元模型如下图所示。 M-P模型把神经元看作n个的输入对应产生1个输出,该模型的函数的表达式如下: 该表达式中W[W1,W2,W3…

人工智能神经网络的应用,人工神经网络最新应用

人工智能在如今人们的现实生活中,都有哪些趣味十足的应用? 人工智能,也被称为AI。研究和开发模拟、扩展和扩展人类智能的理论、方法、技术和应用系统是一门新兴的技术科学。 人工智能是计算机科学的一个分支,它试图理解智能的本…

人工智能实验bp神经网络,BP人工神经网络模型

1、BP人工神经网络方法 (一)方法原理 人工神经网络是由大量的类似人脑神经元的简单处理单元广泛地相互连接而成的复杂的网络系统。理论和实践表明,在信息处理方面,神经网络方法比传统模式识别方法更具有优势。人工神经元是神经网…

介绍人工神经网络的两种常用结构

神经网络有哪些主要分类规则并如何分类? 神经网络模型的分类。 人工神经网络的模型很多,可以按照不同的方法进行分类。其中,常见的两种分类方法是,按照网络连接的拓朴结构分类和按照网络内部的信息流向分类。 1。 按照网络拓朴…

人工神经网络基本构成有哪些,常见的人工神经网络有哪几种

人工神经网络分类方法 从20世纪80年代末期,人工神经网络方法开始应用于遥感图像的自动分类。目前,在遥感图像的自动分类方面,应用和研究比较多的人工神经网络方法主要有以下几种: (1)BP(Back …

简述人工神经网络的基本框架

简述人工神经网络的结构形式 神经网络有多种分类方式,例如,按网络性能可分为连续型与离散型网络,确定型与随机型网络:按网络拓扑结构可分为前向神经网络与反馈神经网络。本章土要简介前向神经网络、反馈神经网络和自组织特征映射神经网络。 …

人工神经网络 神经网络区别_人工神经网络概述

人工神经网络 神经网络区别 Artificial neural networks (ANN) in machine learning (artificial intelligence) are complex compounds of algorithms that work in an organized manner to extract labels or results for a given set of data. It is believed that this tec…

人工神经网络的功能特点,人工神经网络的优缺点

人工神经网络的特点有哪些 人工神经网络的特点和优越性,主要表现在三个方面:第一,具有自学习功能。 例如实现图像识别时,只在先把许多不同的图像样板和对应的应识别的结果输入人工神经网络,网络就会通过自学习功能&a…

人工神经网络基本分类有,人工神经网络基本概念

1、神经网络有哪些主要分类规则并如何分类? 神经网络模型的分类 人工神经网络的模型很多,可以按照不同的方法进行分类。其中,常见的两种分类方法是,按照网络连接的拓朴结构分类和按照网络内部的信息流向分类。 1 按照网络拓朴结构…

人工神经网络模型定义,人工神经网络基本框架

人工神经网络评价法 人工神经元是人工神经网络的基本处理单元,而人工智能的一个重要组成部分又是人工神经网络。人工神经网络是模拟生物神经元系统的数学模型,接受信息主要是通过神经元来进行的。 首先,人工神经元利用连接强度将产生的信号…