最美情侣中文字幕电影,在线麻豆精品传媒,在线网站高清黄,久久黄色视频

歡迎光臨散文網(wǎng) 會員登陸 & 注冊

Linux黑科技|mmap實現(xiàn)詳解(一文看懂~)

2022-10-17 16:36 作者:補給站Linux內(nèi)核  | 我要投稿

故事的開始是這樣的,某天在脈脈上看到有人發(fā)了下面的帖子:

想不到 mmap 都成了黑科技了,為了讓大家都能了解這個黑科技,所以還是寫篇文章來詳細介紹一下 mmap 的實現(xiàn)吧。

其實,源碼分析是比較難寫的,主要有兩個原因:

  • 一方面是源碼實現(xiàn)一般會涉及多個知識點,所以在分析源碼時需要穿插多個知識點,從而增加分析的難度。

  • 另一方面是源碼實現(xiàn)會處理很多細節(jié)問題,這些細節(jié)問題雖然不是設(shè)計的主要框架,但忽略了有時會讓人摸不著頭腦。

所以,為了降低分析的難度和讓讀者能夠更容易看懂,在分析源碼時更注重知識點的實現(xiàn),而在不影響理解的情況下,我會忽略一些細節(jié)問題。而對于穿插其他知識點的時候,會先跳過其實現(xiàn),并且在后續(xù)的文章對其進行分析。

mmap 原理

mmap 的全稱是 memory map,中文意思是 內(nèi)存映射。其用途是將文件映射到內(nèi)存中,然后可以通過對映射區(qū)的內(nèi)存進行讀寫操作,其效果等同于對文件進行讀寫操作。

下面我們通過一幅圖來對 mmap 的原理進行闡述:


從上圖可以看出,mmap 的原理就是將虛擬內(nèi)存空間映射到文件的頁緩存,可知,對文件進行讀寫時需要經(jīng)過頁緩存進行中轉(zhuǎn)的。所以當虛擬內(nèi)存地址映射到文件的頁緩存后,就可以直接通過讀寫映射區(qū)內(nèi)存來對文件進行讀寫操作。


【文章福利】小編推薦自己的Linux內(nèi)核技術(shù)交流群:【891587639】整理了一些個人覺得比較好的學習書籍、視頻資料共享在群文件里面,有需要的可以自行添加哦?。。。ê曨l教程、電子書、實戰(zhàn)項目及代碼)? ??

mmap 實現(xiàn)

在分析 mmap 的實現(xiàn)前,最好先了解其使用方式.

1. 文件映射

當我們使用 mmap() 系統(tǒng)調(diào)用對文件進行映射時,將會觸發(fā)調(diào)用 do_mmap_pgoff() 內(nèi)核函數(shù)來完成工作,我們來看看 do_mmap_pgoff() 函數(shù)的實現(xiàn)(經(jīng)過精簡后):

經(jīng)過精簡后的 do_mmap_pgoff() 函數(shù)主要完成 2 個工作:

  • 首先,調(diào)用 get_unmapped_area() 函數(shù)來獲取進程沒被使用的虛擬內(nèi)存區(qū),并且返回此內(nèi)存區(qū)的首地址。

  • 然后,調(diào)用 mmap_region() 函數(shù)繼續(xù)進行映射操作。

在 32 位的操作系統(tǒng)中,每個進程都有 4GB 的虛擬內(nèi)存空間,應用程序在使用內(nèi)存前,需要先向操作系統(tǒng)發(fā)起申請內(nèi)存的操作。操作系統(tǒng)會從進程的虛擬內(nèi)存空間中查找未被使用的內(nèi)存地址,并且返回給應用程序。 操作系統(tǒng)會記錄進程正在使用中的虛擬內(nèi)存地址,如果內(nèi)存地址沒被登記,說明此內(nèi)存地址是空閑的(未被使用)。

我們繼續(xù)來看看 mmap_region() 函數(shù)的實現(xiàn),代碼如下(經(jīng)過精簡后):

mmap_region() 函數(shù)主要完成以下 4 件事情:

  • 申請一個 vm_area_struct 結(jié)構(gòu)(vma),內(nèi)核使用 vma 來管理進程的虛擬內(nèi)存地址,

  • 設(shè)置 vma 結(jié)構(gòu)各個字段的值。

  • 通過調(diào)用文件對象的 mmap() 回調(diào)函數(shù)來設(shè)置vma結(jié)構(gòu)的 fault() 回調(diào)函數(shù),一般文件對象的 mmap() 回調(diào)函數(shù)為:generic_file_mmap()。

  • 把新創(chuàng)建的 vma 結(jié)構(gòu)連接到進程的虛擬內(nèi)存區(qū)鏈表和紅黑樹中。

內(nèi)核使用 vm_area_struct 結(jié)構(gòu)來管理進程的虛擬內(nèi)存地址。當進程需要使用內(nèi)存時,首先要向操作系統(tǒng)進行申請,操作系統(tǒng)會使用 vm_area_struct 結(jié)構(gòu)來記錄被分配出去的內(nèi)存區(qū)的大小、起始地址和權(quán)限等。

我們來看看 vm_area_struct 結(jié)構(gòu)的定義:

當把文件映射到虛擬內(nèi)存空間時,需要把 vma 結(jié)構(gòu)的 vm_file 字段設(shè)置為要映射的文件對象,然后調(diào)用文件對象的 mmap() 回調(diào)函數(shù)來設(shè)置 vma 結(jié)構(gòu)的 fault() 回調(diào)函數(shù)。

vma 結(jié)構(gòu)的 fault() 回調(diào)函數(shù)的作用是:當虛擬內(nèi)存區(qū)沒有映射到物理內(nèi)存地址時,將會觸發(fā)缺頁異常。而在缺頁異常處理中,將會調(diào)用此回調(diào)函數(shù)來對虛擬內(nèi)存映射到物理內(nèi)存。

我們來看看 generic_file_mmap() 函數(shù)是怎么設(shè)置 vma 結(jié)構(gòu)的 fault() 回調(diào)函數(shù)的:

至此,文件映射的過程已經(jīng)分析完畢。我們來看看其調(diào)用鏈:

2. 缺頁異常

前面介紹了 mmap() 系統(tǒng)調(diào)用的處理過程,可以發(fā)現(xiàn) mmap() 只是將 vma 的 vm_file 字段設(shè)置為被映射的文件對象,并且將 vma 的 fault() 回調(diào)函數(shù)設(shè)置為 filemap_fault()。也就是說,mmap() 系統(tǒng)調(diào)用并沒有對虛擬內(nèi)存進行任何的映射操作。

虛擬內(nèi)存必須映射到物理內(nèi)存才能使用。如果訪問沒有映射到物理內(nèi)存的虛擬內(nèi)存地址,CPU 將會觸發(fā)缺頁異常。也就是說,虛擬內(nèi)存并不能直接映射到磁盤中的文件。

那么 mmap() 是怎么將文件映射到虛擬內(nèi)存中呢?讀寫文件時并不是直接對磁盤上的文件進行操作的,而是通過 頁緩存 作為中轉(zhuǎn)的,而頁緩存就是物理內(nèi)存中的內(nèi)存頁。所以,mmap() 可以通過將文件的頁緩存映射到虛擬內(nèi)存空間來實現(xiàn)對文件的映射。

但我們在 mmap() 系統(tǒng)調(diào)用的實現(xiàn)中,也沒看到將文件頁緩存映射到虛擬內(nèi)存空間。那么映射過程是在什么時候發(fā)生的呢?

答案就是:缺頁異常 。

由于 mmap() 系統(tǒng)調(diào)用并沒有直接將文件的頁緩存映射到虛擬內(nèi)存中,所以當訪問到?jīng)]有映射的虛擬內(nèi)存地址時,將會觸發(fā) 缺頁異常。當 CPU 觸發(fā)缺頁異常時,將會調(diào)用 do_page_fault() 函數(shù)來修復觸發(fā)異常的虛擬內(nèi)存地址。

我們主要來看看 do_page_fault() 函數(shù)對文件映射的實現(xiàn)部分,其調(diào)用鏈如下:

所以我們直接來看看 __do_fault() 函數(shù)的實現(xiàn):

__do_fault() 函數(shù)對處理文件映射部分主要分為 3 個步驟:

  • 調(diào)用虛擬內(nèi)存管理區(qū)結(jié)構(gòu)(vma)的 fault() 回調(diào)函數(shù)(也就是 filemap_fault() 函數(shù))來獲取到文件的頁緩存。

  • 通過頁緩存的物理內(nèi)存頁來生成一個頁表項值,

  • 將虛擬內(nèi)存地址映射到頁緩存的物理內(nèi)存頁(也就是將進程的頁表項設(shè)置為上面生成的頁表項的值)。

對于 filemap_fault() 函數(shù)是怎樣讀取文件頁緩存的,本文不作解釋,有興趣的可以自行閱讀源碼。

最后,我們以一幅圖來描述一下虛擬內(nèi)存是如何與文件進行映射的:




從上圖可以看出,mmap() 是通過將虛擬內(nèi)存地址映射到文件的頁緩存來實現(xiàn)的。當對映射后的虛擬內(nèi)存進行讀寫操作時,其效果等價于直接對文件的頁緩存進行讀寫操作。對文件的頁緩存進行讀寫操作,也等價于對文件進行讀寫操作。





Linux黑科技|mmap實現(xiàn)詳解(一文看懂~)的評論 (共 條)

分享到微博請遵守國家法律
博野县| 且末县| 出国| 临夏市| 临清市| 团风县| 龙山县| 黄冈市| 武胜县| 康保县| 云南省| 东丽区| 临江市| 万年县| 理塘县| 米林县| 乐东| 陇西县| 无锡市| 奉新县| 禹州市| 临江市| 高唐县| 德昌县| 乐至县| 雷波县| 湘乡市| 高清| 湟中县| 健康| 阳高县| 斗六市| 澄江县| 五原县| 临潭县| 隆子县| 宁乡县| 云林县| 永登县| 嘉祥县| 金沙县|