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

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

完全分析Linux mmap原理(看完悟了)

2022-05-04 13:29 作者:補給站Linux內(nèi)核  | 我要投稿
  • 內(nèi)存映射是一個很有趣的思想,我們都知道操作系統(tǒng)分為用戶態(tài)和內(nèi)核態(tài),用戶態(tài)是不能直接和物理設(shè)備打交道,如果我們用戶空間想訪問硬盤的一塊區(qū)域數(shù)據(jù),則需要兩次拷貝(硬盤->內(nèi)核->用戶),但是內(nèi)存映射的設(shè)計只需要發(fā)生一次拷貝,大大提高了讀取數(shù)據(jù)的效率。那么內(nèi)存映射的原理和內(nèi)核是如何實現(xiàn)的呢?

1. 內(nèi)存映射概念

  • 內(nèi)存映射,簡而言之就是將用戶空間的一段內(nèi)存區(qū)域映射到內(nèi)核空間,映射成功后,用戶對這段內(nèi)存區(qū)域的修改可以直接反映到內(nèi)核空間,同樣,內(nèi)核空間對這段區(qū)域的修改也直接反映給用戶空間,對于用戶空間和內(nèi)核空間兩者之間需要進(jìn)行大量數(shù)據(jù)傳輸?shù)炔僮鞯脑捫适欠浅8叩?。如下圖所示


  • 實現(xiàn)這樣的映射后,進(jìn)程就可以采用指針的方式讀寫操作這一段內(nèi)存,而系統(tǒng)會自動回寫臟頁到對應(yīng)的文件磁盤上,就可以完成對于文件的操作,而不需要再調(diào)用read/write等系統(tǒng)調(diào)用函數(shù)。同時,內(nèi)核空間對于這段區(qū)域的修改也可以直接反映到用戶空間,從而可以實現(xiàn)不同進(jìn)程間的文件共享。

  • mmap/munmap 接口是常用的內(nèi)存映射的系統(tǒng)調(diào)用接口,無論是在用戶空間分配內(nèi)存、讀寫大文件、連接動態(tài)庫文件,還是多進(jìn)程間共享內(nèi)存,都可以看到其身影,其聲明如下:


#include <sys/mman.h> void* mmap(void* start, size_t length, int prot, int flags, int fd, off_t offset); int munmap(void *addr, size_t length);


條件:

  • mmap()必須以PAGE_SIZE為單位進(jìn)行映射,而內(nèi)存也只能以頁為單位進(jìn)行映射,若要映射非PAGE_SIZE整數(shù)倍的地址范圍,要先進(jìn)行內(nèi)存對齊,強行以PAGE_SIZE的倍數(shù)大小進(jìn)行映射。

參數(shù)說明:

  1. start:映射區(qū)的開始地址,設(shè)置為0時表示由系統(tǒng)決定映射區(qū)的起始地址。

  2. length:映射區(qū)的長度。//長度單位是 以字節(jié)為單位,不足一內(nèi)存頁按一內(nèi)存頁處理

  3. prot:期望的內(nèi)存保護(hù)標(biāo)志,不能與文件的打開模式?jīng)_突。是以下的某個值,可以通過or運算合理地組合在一起

  • PROT_EXEC: 表示映射的頁面是可以執(zhí)行的

  • PROT_READ:表示映射的頁面是可以讀取的

  • PROT_WRITE :表示映射的頁面是可以寫入的

  • PROT_NONE :表示映射的頁面是不可訪問的

4. flags:指定映射對象的類型,映射選項和映射頁是否可以共享。它的值可以是一個或者多個以下位的組合體

  • MAP_SHARED:創(chuàng)建一個共享映射的區(qū)域,多個進(jìn)程可以通過共享映射的方式來映射一個文件,這樣其他進(jìn)程也可以看到映射內(nèi)容的改變,修改后的內(nèi)容會同步到磁盤文件

  • MAP_PRIVATE:創(chuàng)建一個私有的寫時復(fù)制的映射,多個進(jìn)程可以通過私有映射方式來映射一個文件,其他的進(jìn)程不會看到映射文件內(nèi)容的改變,修改后也不會同步到磁盤中

  • MAP_ANONYMOUS:創(chuàng)建一個匿名映射,即沒有關(guān)聯(lián)到文件的映射

  • MAP_FIXED:

  • MAP_POPULATE:提前遇到文件內(nèi)容到映射區(qū)

5. fd:mmap映射釋放和文件相關(guān)聯(lián),可以分為匿名映射和文件映射

  • 文件映射:將一個普通文件的全部或者一部分映射到進(jìn)程的虛擬內(nèi)存中。映射后,進(jìn)程就可以直接在對應(yīng)的內(nèi)存區(qū)域操作文件內(nèi)容!

  • 匿名映射:匿名映射沒有對應(yīng)的文件或者對應(yīng)的文件時虛擬文件(如:/dev/zero),映射后會把內(nèi)存分頁全部初始化為0。

6. offset:被映射對象內(nèi)容的起點


【文章福利】小編推薦自己的Linux內(nèi)核技術(shù)交流群:【891587639】整理了一些個人覺得比較好的學(xué)習(xí)書籍、視頻資料共享在群文件里面,有需要的可以自行添加哦!??!前100名進(jìn)群領(lǐng)取,額外贈送一份價值699的內(nèi)核資料包(含視頻教程、電子書、實戰(zhàn)項目及代碼)?



  • 成功執(zhí)行時,mmap()返回被映射區(qū)的指針,munmap()返回0。失敗時,mmap()返回MAP_FAILED[其值為(void *)-1],munmap返回-1。

  • 根據(jù)文件關(guān)聯(lián)性和映射區(qū)域示范共享等屬性,其分為


2. 源碼分析

  • 查看 mmap 的系統(tǒng)調(diào)用的代碼實現(xiàn),其流程為 sys_mmp_pg_off(),最終會調(diào)用達(dá)到 do_mmap_pgoff,該函數(shù)使一個體系結(jié)構(gòu)無關(guān)的代碼,定義在 mm/mmap.c 中,

  • 首先我們來看看 do_mmap(),是整個 mmap() 的具體操作函數(shù)

unsigned long do_mmap(struct file *file, unsigned long addr,
 ? unsigned long len, unsigned long prot,
 ? unsigned long flags, vm_flags_t vm_flags,
 ? unsigned long pgoff, unsigned long *populate)
{
 struct mm_struct *mm = current->mm; ? ? ? ?//獲取該進(jìn)程的memory descriptor
 int pkey = 0;

 *populate = 0;
 //函數(shù)對傳入的參數(shù)進(jìn)行一系列檢查, 假如任一參數(shù)出錯,都會返回一個errno
 if (!len)
 ?return -EINVAL;

 /*
 ?* Does the application expect PROT_READ to imply PROT_EXEC?
 ?*
 ?* (the exception is when the underlying filesystem is noexec
 ?* ?mounted, in which case we dont add PROT_EXEC.)
 ?*/
 if ((prot & PROT_READ) && (current->personality & READ_IMPLIES_EXEC))
 ?if (!(file && path_noexec(&file->f_path)))
 ? prot |= PROT_EXEC;
 //假如沒有設(shè)置MAP_FIXED標(biāo)志,且addr小于mmap_min_addr, 因為可以修改addr, 所以就需要將addr設(shè)為mmap_min_addr的頁對齊后的地址
 if (!(flags & MAP_FIXED))
 ?addr = round_hint_to_min(addr);

 /* Careful about overflows.. */
 len = PAGE_ALIGN(len); ? ? ? ? //進(jìn)行Page大小的對齊
 if (!len)
 ?return -ENOMEM;

 /* offset overflow? */
 if ((pgoff + (len >> PAGE_SHIFT)) < pgoff)
 ?return -EOVERFLOW;

 /* Too many mappings? */
 if (mm->map_count > sysctl_max_map_count) ? ?//判斷該進(jìn)程的地址空間的虛擬區(qū)間數(shù)量是否超過了限制
 ?return -ENOMEM;

 //get_unmapped_area從當(dāng)前進(jìn)程的用戶空間獲取一個未被映射區(qū)間的起始地址
 addr = get_unmapped_area(file, addr, len, pgoff, flags);
 if (offset_in_page(addr)) ? ? ? ?//檢查addr是否有效
 ?return addr;

 if (prot == PROT_EXEC) {
 ?pkey = execute_only_pkey(mm);
 ?if (pkey < 0)
 ? pkey = 0;
 }

 /* Do simple checking here so the lower-level routines won't have
 ?* to. we assume access permissions have been handled by the open
 ?* of the memory object, so we don't do any here.
 ?*/
 vm_flags |= calc_vm_prot_bits(prot, pkey) | calc_vm_flag_bits(flags) |
 ? mm->def_flags | VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC;
 //假如flags設(shè)置MAP_LOCKED,即類似于mlock()將申請的地址空間鎖定在內(nèi)存中, 檢查是否可以進(jìn)行l(wèi)ock
 if (flags & MAP_LOCKED)
 ?if (!can_do_mlock())
 ? return -EPERM;

 if (mlock_future_check(mm, vm_flags, len))
 ?return -EAGAIN;

 if (file) { ? ? ? ? ?// file指針不為nullptr, 即從文件到虛擬空間的映射
 ?struct inode *inode = file_inode(file); ? //獲取文件的inode

 ?switch (flags & MAP_TYPE) { ? ? ? //根據(jù)標(biāo)志指定的map種類,把為文件設(shè)置的訪問權(quán)考慮進(jìn)去
 ?case MAP_SHARED:
 ? if ((prot&PROT_WRITE) && !(file->f_mode&FMODE_WRITE))
 ? ?return -EACCES;

 ? /*
 ? ?* Make sure we don't allow writing to an append-only
 ? ?* file..
 ? ?*/
 ? if (IS_APPEND(inode) && (file->f_mode & FMODE_WRITE))
 ? ?return -EACCES;

 ? /*
 ? ?* Make sure there are no mandatory locks on the file.
 ? ?*/
 ? if (locks_verify_locked(file))
 ? ?return -EAGAIN;

 ? vm_flags |= VM_SHARED | VM_MAYSHARE;
 ? if (!(file->f_mode & FMODE_WRITE))
 ? ?vm_flags &= ~(VM_MAYWRITE | VM_SHARED);

 ? /* fall through */
 ?case MAP_PRIVATE:
 ? if (!(file->f_mode & FMODE_READ))
 ? ?return -EACCES;
 ? if (path_noexec(&file->f_path)) {
 ? ?if (vm_flags & VM_EXEC)
 ? ? return -EPERM;
 ? ?vm_flags &= ~VM_MAYEXEC;
 ? }

 ? if (!file->f_op->mmap)
 ? ?return -ENODEV;
 ? if (vm_flags & (VM_GROWSDOWN|VM_GROWSUP))
 ? ?return -EINVAL;
 ? break;

 ?default:
 ? return -EINVAL;
 ?}
 } else {
 ?switch (flags & MAP_TYPE) {
 ?case MAP_SHARED:
 ? if (vm_flags & (VM_GROWSDOWN|VM_GROWSUP))
 ? ?return -EINVAL;
 ? /*
 ? ?* Ignore pgoff.
 ? ?*/
 ? pgoff = 0;
 ? vm_flags |= VM_SHARED | VM_MAYSHARE;
 ? break;
 ?case MAP_PRIVATE:
 ? /*
 ? ?* Set pgoff according to addr for anon_vma.
 ? ?*/
 ? pgoff = addr >> PAGE_SHIFT;
 ? break;
 ?default:
 ? return -EINVAL;
 ?}
 }

 /*
 ?* Set 'VM_NORESERVE' if we should not account for the
 ?* memory use of this mapping.
 ?*/
 if (flags & MAP_NORESERVE) {
 ?/* We honor MAP_NORESERVE if allowed to overcommit */
 ?if (sysctl_overcommit_memory != OVERCOMMIT_NEVER)
 ? vm_flags |= VM_NORESERVE;

 ?/* hugetlb applies strict overcommit unless MAP_NORESERVE */
 ?if (file && is_file_hugepages(file))
 ? vm_flags |= VM_NORESERVE;
 }
 //一頓檢查和配置,調(diào)用核心的代碼mmap_region
 addr = mmap_region(file, addr, len, vm_flags, pgoff);
 if (!IS_ERR_VALUE(addr) &&
 ? ? ((vm_flags & VM_LOCKED) ||
 ? ? ?(flags & (MAP_POPULATE | MAP_NONBLOCK)) == MAP_POPULATE))
 ?*populate = len;
 return addr;
}

do_mmap() 根據(jù)用戶傳入的參數(shù)做了一系列的檢查,然后根據(jù)參數(shù)初始化 vm_area_struct 的標(biāo)志 vm_flags,vma->vm_file = get_file(file) 建立文件與vma的映射, mmap_region() 負(fù)責(zé)創(chuàng)建虛擬內(nèi)存區(qū)域:

unsigned long mmap_region(struct file *file, unsigned long addr,
 ?unsigned long len, vm_flags_t vm_flags, unsigned long pgoff)
{
 struct mm_struct *mm = current->mm; ? ? //獲取該進(jìn)程的memory descriptor
 struct vm_area_struct *vma, *prev;
 int error;
 struct rb_node **rb_link, *rb_parent;
 unsigned long charged = 0;

 /* 檢查申請的虛擬內(nèi)存空間是否超過了限制 */
 if (!may_expand_vm(mm, vm_flags, len >> PAGE_SHIFT)) {
 ?unsigned long nr_pages;

 ?/*
 ? * MAP_FIXED may remove pages of mappings that intersects with
 ? * requested mapping. Account for the pages it would unmap.
 ? */
 ?nr_pages = count_vma_pages_range(mm, addr, addr + len);

 ?if (!may_expand_vm(mm, vm_flags,
 ? ? (len >> PAGE_SHIFT) - nr_pages))
 ? return -ENOMEM;
 }

 /* 檢查[addr, addr+len)的區(qū)間是否存在映射空間,假如存在重合的映射空間需要munmap ?*/
 while (find_vma_links(mm, addr, addr + len, &prev, &rb_link,
 ? ? ? ? &rb_parent)) {
 ?if (do_munmap(mm, addr, len))
 ? return -ENOMEM;
 }

 /*
 ?* Private writable mapping: check memory availability
 ?*/
 if (accountable_mapping(file, vm_flags)) {
 ?charged = len >> PAGE_SHIFT;
 ?if (security_vm_enough_memory_mm(mm, charged))
 ? return -ENOMEM;
 ?vm_flags |= VM_ACCOUNT;
 }

 //檢查是否可以合并[addr, addr+len)區(qū)間內(nèi)的虛擬地址空間vma
 vma = vma_merge(mm, prev, addr, addr + len, vm_flags,
 ? NULL, file, pgoff, NULL, NULL_VM_UFFD_CTX);
 if (vma) ? ? ? //假如合并成功,即使用合并后的vma, 并跳轉(zhuǎn)至out
 ?goto out;
 //如果不能和已有的虛擬內(nèi)存區(qū)域合并,通過Memory Descriptor來申請一個vma
 vma = kmem_cache_zalloc(vm_area_cachep, GFP_KERNEL);
 if (!vma) {
 ?error = -ENOMEM;
 ?goto unacct_error;
 }
 //初始化vma
 vma->vm_mm = mm;
 vma->vm_start = addr;
 vma->vm_end = addr + len;
 vma->vm_flags = vm_flags;
 vma->vm_page_prot = vm_get_page_prot(vm_flags);
 vma->vm_pgoff = pgoff;
 INIT_LIST_HEAD(&vma->anon_vma_chain);

 if (file) { //假如指定了文件映射 
 ?if (vm_flags & VM_DENYWRITE) { ? //映射的文件不允許寫入,調(diào)用deny_write_accsess(file)排斥常規(guī)的文件操作
 ? error = deny_write_access(file);
 ? if (error)
 ? ?goto free_vma;
 ?}
 ?if (vm_flags & VM_SHARED) { ? //映射的文件允許其他進(jìn)程可見, 標(biāo)記文件為可寫
 ? error = mapping_map_writable(file->f_mapping);
 ? if (error)
 ? ?goto allow_write_and_free_vma;
 ?}

 ?//遞增File的引用次數(shù),返回File賦給vma
 ?vma->vm_file = get_file(file);
 ?error = file->f_op->mmap(file, vma); ?//調(diào)用文件系統(tǒng)指定的mmap函數(shù)
 ?if (error)
 ? goto unmap_and_free_vma;

 ?/* Can addr have changed??
 ? *
 ? * Answer: Yes, several device drivers can do it in their
 ? * ? ? ? ? f_op->mmap method. -DaveM
 ? * Bug: If addr is changed, prev, rb_link, rb_parent should
 ? * ? ? ?be updated for vma_link()
 ? */
 ?WARN_ON_ONCE(addr != vma->vm_start);

 ?addr = vma->vm_start;
 ?vm_flags = vma->vm_flags;
 } else if (vm_flags & VM_SHARED) {
 ?error = shmem_zero_setup(vma); ?//假如標(biāo)志為VM_SHARED,但沒有指定映射文件,需要調(diào)用shmem_zero_setup(),實際映射的文件是dev/zero
 ?if (error)
 ? goto free_vma;
 }
 //將申請的新vma加入mm中的vma鏈表
 vma_link(mm, vma, prev, rb_link, rb_parent);
 /* Once vma denies write, undo our temporary denial count */
 if (file) {
 ?if (vm_flags & VM_SHARED)
 ? mapping_unmap_writable(file->f_mapping);
 ?if (vm_flags & VM_DENYWRITE)
 ? allow_write_access(file);
 }
 file = vma->vm_file;
out:
 perf_event_mmap(vma);
 //更新進(jìn)程的虛擬地址空間mm
 vm_stat_account(mm, vm_flags, len >> PAGE_SHIFT);
 if (vm_flags & VM_LOCKED) {
 ?if (!((vm_flags & VM_SPECIAL) || is_vm_hugetlb_page(vma) ||
 ? ? vma == get_gate_vma(current->mm)))
 ? mm->locked_vm += (len >> PAGE_SHIFT);
 ?else
 ? vma->vm_flags &= VM_LOCKED_CLEAR_MASK;
 }

 if (file)
 ?uprobe_mmap(vma);

 /*
 ?* New (or expanded) vma always get soft dirty status.
 ?* Otherwise user-space soft-dirty page tracker won't
 ?* be able to distinguish situation when vma area unmapped,
 ?* then new mapped in-place (which must be aimed as
 ?* a completely new data area).
 ?*/
 vma->vm_flags |= VM_SOFTDIRTY;

 vma_set_page_prot(vma);

 return addr;

unmap_and_free_vma:
 vma->vm_file = NULL;
 fput(file);

 /* Undo any partial mapping done by a device driver. */
 unmap_region(mm, vma, prev, vma->vm_start, vma->vm_end);
 charged = 0;
 if (vm_flags & VM_SHARED)
 ?mapping_unmap_writable(file->f_mapping);
allow_write_and_free_vma:
 if (vm_flags & VM_DENYWRITE)
 ?allow_write_access(file);
free_vma:
 kmem_cache_free(vm_area_cachep, vma);
unacct_error:
 if (charged)
 ?vm_unacct_memory(charged);
 return error;
}
  • mmap_region() 調(diào)用了 call_mmap(file, vma),call_mmap 根據(jù)文件系統(tǒng)的類型選擇適配的 mmap() 函數(shù),我們選擇目前常用的ext4,ext4_file_mmap() 是ext4對應(yīng)的mmap, 功能非常簡單,更新了file的修改時間(file_accessed(flie)),將對應(yīng)的operation賦給 vma->vm_flags,后面的文件系統(tǒng)章節(jié)在學(xué)習(xí)這塊。

  • 通過分析mmap的源碼我們發(fā)現(xiàn)在調(diào)用 mmap() 的時候僅僅申請一個 vm_area_struct 來建立文件與虛擬內(nèi)存的映射,并沒有建立虛擬內(nèi)存與物理內(nèi)存的映射。假如沒有設(shè)置 MAP_POPULATE 標(biāo)志位,Linux并不在調(diào)用 mmap() 時就為進(jìn)程分配物理內(nèi)存空間,直到下次真正訪問地址空間時發(fā)現(xiàn)數(shù)據(jù)不存在于物理內(nèi)存空間時,觸發(fā) Page Fault 即缺頁中斷,Linux才會將缺失的Page換入內(nèi)存空間。其代碼流程圖如下所示


3. 應(yīng)用場景

  • 對于傳統(tǒng)的linux系統(tǒng)文件操作是如何的呢?首選我們來看看工作流是如何的,其流程如下圖所示


其特點為

  1. 使用頁緩存機制,提高讀寫效率和保護(hù)磁盤

  2. 讀文件時,先將文件從磁盤拷貝到緩存,由于頁緩存區(qū)是在內(nèi)核空間,不能被用戶空間直接訪問,所以需要將頁緩存區(qū)數(shù)據(jù)再次拷貝到用戶空間,有2次文件拷貝工作

  • 下面來看看使用內(nèi)存映射文件讀/寫的流程,其流程圖如下圖所示


其特點為:

  1. 用戶空間與內(nèi)核空間的交互式通過映射的區(qū)域直接交互,用內(nèi)存的讀取代替I/O讀寫,文件讀寫效率高

  2. 數(shù)據(jù)拷貝次數(shù)少,對文件的讀取操作跨過頁緩存,減少了數(shù)據(jù)拷貝一次,效率提高

  3. 可實現(xiàn)高效的大規(guī)模數(shù)據(jù)傳輸

  • 在Linux系統(tǒng)中,根據(jù)內(nèi)存映射的本質(zhì)和特點,其應(yīng)用場景在于

  1. 實現(xiàn)內(nèi)存共享,如跨進(jìn)程通信

  2. 提高數(shù)據(jù)讀/寫效率:如讀寫操作

  • 對于進(jìn)程間的通信,其工作流程如下圖所示


  1. 創(chuàng)建一塊共享的接收區(qū),實現(xiàn)地址映射關(guān)系

  2. 發(fā)送進(jìn)程數(shù)據(jù)到自身的虛擬內(nèi)存區(qū)域,數(shù)據(jù)拷貝1次

  3. 由于發(fā)送進(jìn)程的虛擬地址空間與接收進(jìn)程的虛擬內(nèi)存地址存在映射關(guān)系,所以發(fā)送到的數(shù)據(jù)也存放到接收進(jìn)程的虛擬內(nèi)存中,即實現(xiàn)了跨進(jìn)程間通信

4. 總結(jié)

  • 內(nèi)存映射的讀寫操作主要的過程如下:

  1. 創(chuàng)建虛擬映射區(qū)域,其在當(dāng)前進(jìn)程的虛擬地址空間中,尋找一段滿足大小要求的虛擬地址,并且為此虛擬地址分配一個虛擬內(nèi)存區(qū)域(vm_area_struct結(jié)構(gòu)),初始化該虛擬內(nèi)存區(qū)域,插入到進(jìn)程虛擬地址區(qū)域的鏈表和紅黑樹中

  2. 實現(xiàn)地址映射關(guān)系,建立頁表,該過程在mmap函數(shù)中并未實現(xiàn),此時只是創(chuàng)建了映射關(guān)系,并不將任何文件數(shù)據(jù)拷貝至主存中,真正的數(shù)據(jù)拷貝是通過進(jìn)程發(fā)起讀寫操作時

  3. 進(jìn)程訪問該映射空間,實現(xiàn)文件內(nèi)容到物理內(nèi)存的數(shù)據(jù)拷貝,當(dāng)進(jìn)程讀寫訪問該映射地址時,如果進(jìn)程寫操作改變了內(nèi)容,并不會立即更新,而是一定時間后系統(tǒng)會自動會寫臟數(shù)據(jù)到對應(yīng)硬盤的地址空間

  • 使用mmap來創(chuàng)建文件映射,由于只建立了進(jìn)程地址空間VMA,并沒有馬上分配page cache和建立映射關(guān)系。那么就會導(dǎo)致一個問題,當(dāng)創(chuàng)建一個很大的VMA,會頻繁發(fā)生缺頁中斷。

  1. 內(nèi)存映射機制mmap是POSIX標(biāo)準(zhǔn)的系統(tǒng)調(diào)用,有匿名映射和文件映射兩種。

  2. 匿名映射使用進(jìn)程的虛擬內(nèi)存空間,它和malloc(3)類似,實際上有些malloc實現(xiàn)會使用mmap匿名映射分配內(nèi)存,不過匿名映射不是POSIX標(biāo)準(zhǔn)中規(guī)定的。

  3. 文件映射有MAP_PRIVATE和MAP_SHARED兩種。前者使用COW的方式,把文件映射到當(dāng)前的進(jìn)程空間,修改操作不會改動源文件。后者直接把文件映射到當(dāng)前的進(jìn)程空間,所有的修改會直接反應(yīng)到文件的page cache,然后由內(nèi)核自動同步到映射文件上。

  • 相比于IO函數(shù)調(diào)用,基于文件的mmap的一大優(yōu)點是把文件映射到進(jìn)程的地址空間,避免了數(shù)據(jù)從用戶緩沖區(qū)到內(nèi)核page cache緩沖區(qū)的復(fù)制過程;當(dāng)然還有一個優(yōu)點就是不需要頻繁的read/write系統(tǒng)調(diào)用。



完全分析Linux mmap原理(看完悟了)的評論 (共 條)

分享到微博請遵守國家法律
沛县| 永城市| 全椒县| 亳州市| 定州市| 寻乌县| 牙克石市| 瓦房店市| 长汀县| 堆龙德庆县| 沙湾县| 麦盖提县| 屏东县| 鞍山市| 略阳县| 凤城市| 波密县| 呈贡县| 连云港市| 任丘市| 平乡县| 承德市| 宁远县| 壶关县| 客服| 江西省| 中方县| 平原县| 祁东县| 定安县| 临猗县| 金昌市| 洮南市| 泾阳县| 本溪市| 揭东县| 杭锦旗| 五家渠市| 玉林市| 镇巴县| 连江县|