深入解析Mac OS X & iOS 操作系統(tǒng) 學(xué)習筆記(十三)

Mach 虛擬內(nèi)存

在內(nèi)核管理最重要的資源中,出了CPU本身酌壕,就是內(nèi)存了卵牍。Mach 和所有內(nèi)核一樣沦泌,代碼中有很大一部分都在負責高效地管理內(nèi)存(virtual memory谢谦,VM)萝衩。

虛擬內(nèi)存架構(gòu)

虛擬內(nèi)存的抽象是Mach 中提供的最重要的機制猩谊,虛擬內(nèi)存的抽象是通過內(nèi)存對象(memory object)和分頁器(pager)的形式提供的牌捷。和調(diào)度以及Mach 原語原語暗甥,我們這里要面對的是一個抽象層遮怜,這里抽象層提供了供上層使用的底層原語锯梁。在XNU 中,這個“上層”就是BSD層剥懒。
Mach 虛擬內(nèi)存的實現(xiàn)非常全面而且通用初橘。這部分由兩個層次構(gòu)成:一層是和硬件相關(guān)的部分充岛,另一層構(gòu)建在這一層之上崔梗,是和硬件無關(guān)的公共層。OS X 和 iOS 使用的幾乎一樣的底層機制扔亥,硬件無關(guān)層(以及之上的BSD 層中的機制)都是一樣的旅挤,只有架構(gòu)相關(guān)部分的代碼改為適合ARM 虛擬內(nèi)存的語義粘茄。

虛擬內(nèi)存全貌

Mach 的 虛擬內(nèi)存子系統(tǒng)可以說是和其要管理的虛擬內(nèi)存一樣復(fù)雜和充滿了各種細節(jié)秕脓。然后從高層次看,可以看到兩個層次:一個是虛擬內(nèi)存的層次嘹朗,一個是物理內(nèi)存的層次屹培。

  • 虛擬內(nèi)存層
    虛擬內(nèi)存這一層完全以一種機器無關(guān)的方式來管理虛擬內(nèi)存褪秀。這一層通過幾種關(guān)鍵的抽象表示虛擬內(nèi)存:

  • vm_map:表示任務(wù)地址空間內(nèi)的一個或多個虛擬內(nèi)存區(qū)域薛训。每一個區(qū)域都是有一個獨立的條目vm_map_entry 表示乙埃。這些條目又一個雙向鏈表vm_map_links維護。

  • vm_map_entry:這是關(guān)鍵的數(shù)據(jù)結(jié)構(gòu)甫何,盡管只有在包含這個結(jié)構(gòu)的映射的上下文中才會訪問到這個結(jié)構(gòu)辙喂。每一個vm_map_entry 都表示了虛擬內(nèi)存中一塊連續(xù)的區(qū)域(region)巍耗。每一個這樣的區(qū)域都可以通過指定的訪問保護權(quán)限進行保護(和虛擬內(nèi)存頁面采用同樣的權(quán)限)渐排。任務(wù)之間可以共享區(qū)域飞盆。vm_map_entry 通常指向一個vm_object,但是也可以指向一個嵌套的vm_map孽水,即子映射(submap)女气。

  • vm_object:用于將vm_map_entry 和實際支撐的內(nèi)存關(guān)聯(lián)起來炼鞠。這個數(shù)據(jù)結(jié)構(gòu)包含一個vm_page 的鏈表,還包含一個用于訪問正確分頁器的Mach 端口(稱為memory_object)谒主,通過這個分頁器進行頁面的獲取或清理操作霎肯。

  • vm_page:vm_page 真正表示了vn_object 或部分vm_object(由vm_object中的偏移量表示)。vm_page 可以有多種狀態(tài):駐留內(nèi)存搂捧、交換出允跑、加密聋丝、干凈和臟等拌屏。
    Mach 允許使用多個分頁器。事實上每篷,默認就存在3~4個分頁器焦读。Mach 的分頁器以外部實體的形式存在:是專業(yè)的任務(wù)矗晃,有點類似于其他系統(tǒng)上的內(nèi)核交換(kernel-swapping)線程宴倍。Mach 的設(shè)計允許分頁器和內(nèi)核任務(wù)隔離開鸵贬,設(shè)置允許用戶態(tài)任務(wù)作為分頁器。類似地兆衅,底層的后備存儲也可以駐留在磁盤交換文件中(通過OS X 中的 default_pager 處理)羡亩,可以映射到一個文件(由vnode_pager處理),可以是一個設(shè)備(由device_pager 處理)雷袋。注意:在Mach 中片排,每一個分頁器處理的都是屬于這個分頁器的頁面的請求速侈,但是這些請求必須通過pageout 守護程序發(fā)出倚搬。這些守護程序(實際上就是內(nèi)核線程)維護內(nèi)核的頁面表乾蛤,并且判定哪些頁面需要被清除出去家卖。因此,這些守護程序維護的分頁策略和分頁器實現(xiàn)的分頁操作是分開的趴樱。

  • 物理內(nèi)存層:物理內(nèi)存的頁面處理的是虛擬內(nèi)存到物理內(nèi)存的映射酪捡,因為虛擬內(nèi)存中的內(nèi)容最終總要存儲在某個地方逛薇。這一層面只有一個抽象,那就是pmap啤呼,不過這個抽象非常重要呢袱,因為提供了機器無關(guān)的接口产捞。這個接口隱藏了底層平臺的細節(jié),底層的細節(jié)需要在處理器層次進行分頁操作焊唬,其中要處理的對象包括硬件頁表項(page table entry赶促,PTE)、翻譯查找表(translation lookaside buffer嗦哆,TLB)等婿滓。

虛擬內(nèi)存概述

每一個Mach 任務(wù)都要自己的虛擬內(nèi)存空間凸主,任務(wù)的struct task 中的 map 字段保存的就是這個虛擬內(nèi)存空間卿吐。
vm_page_entry 中最關(guān)鍵的元素是vm_map_object,這是一個聯(lián)合體箭窜,既可以包含另一個vm_map(作為子映射)衍腥,也可以包含一個vm_object_t(由于這是一個聯(lián)合體,所以具體的內(nèi)容需要用布爾字段is_sub_map 來判斷)婆咸。vm_object 是一個巨大的數(shù)據(jù)結(jié)構(gòu)擅耽,其中包含了處理底層虛擬內(nèi)存所需要的所有數(shù)據(jù)。vm_object的數(shù)據(jù)結(jié)構(gòu)中的大部分字段都是用位表示的標志憾儒。這些字段表示了底層的內(nèi)存狀態(tài)(聯(lián)動起趾、物理連續(xù)和持久化等狀態(tài))和一些計數(shù)器(引用計數(shù)警儒、駐留計數(shù)和聯(lián)動計數(shù)等)。不過有3個字段需要特別注意:

  • memq:vm_page 對象的鏈表边琉,每一項都表示一個駐留內(nèi)存的虛擬內(nèi)存頁面变姨。盡管一個對象可以表示一個單獨的頁面,但是多數(shù)情況下一個對象可以包含多個頁面定欧,所以每一個頁面關(guān)聯(lián)到一個對象時都會有一個偏移值
  • page:memory_object 對象砍鸠,這是指向分頁器的Mach 端口。分頁器將未駐留內(nèi)存的頁面關(guān)聯(lián)到后備存儲类茂,后備存儲可以是內(nèi)存映射的文件、設(shè)備和交換文件厚骗,后備存儲保存了沒有駐留內(nèi)存的頁面领舰。換句話說,分頁器(可以有多個)負責將數(shù)據(jù)從后備存儲移入內(nèi)存以及將數(shù)據(jù)從內(nèi)存移出到后備存儲舍咖。分頁器對于虛擬內(nèi)存子系統(tǒng)來說極為重要
  • internal:vm_page 中眾多標志位之一排霉,如果這個位為真民轴,那么表示這個對象是由內(nèi)核內(nèi)部使用的后裸。這個標志位的值決定了對象中的頁面會進入哪一個pageout隊列

物理內(nèi)存管理

盡管內(nèi)核和用戶空間一樣微驶,基本上只在虛擬地址空間內(nèi)操作,但是虛擬內(nèi)存最終還是要翻譯為物理地址的篇恒。機器的RAM 實際上是虛擬內(nèi)存中開的窗口梁呈,允許程序訪問虛擬內(nèi)存是有限的官卡,而且通常是不連續(xù)的區(qū)域寻咒,這些區(qū)域的上線就是機器上安裝的內(nèi)存。而虛擬內(nèi)存中其他部分則要么延遲分配饭寺,要么共享艰匙,要么被交換到外部存儲中抹恳,外部存儲通常是磁盤奋献。
然而虛擬內(nèi)存和具體的底層架構(gòu)相關(guān)。盡管虛擬內(nèi)存和物理內(nèi)存的概念在所有架構(gòu)上本周都是一樣的糖埋,但是具體的實現(xiàn)細節(jié)則各有千秋瞳别。XNU 構(gòu)建與Mach 的物理內(nèi)存抽象層之上洒试,這個的抽象層成為pmap垒棋。pmap 從設(shè)計上對物理內(nèi)存提供了一個統(tǒng)一的接口痪宰,屏蔽了架構(gòu)相關(guān)的區(qū)別。這對于XNU來說非常有用扮饶,因為XNU支持的物理內(nèi)存的架構(gòu)包括以前的PowerPC乍构,現(xiàn)在主要是Intel哥遮,然后在iOS 中還支持ARM眠饮。

pmap 的 API

Mach 的pmap 層邏輯上由一下兩個子層構(gòu)成:

  • 機器無關(guān)層:提供了一組基本上和及其無關(guān)的API仪召。只要求及其支持基本的虛擬內(nèi)存分頁的概念。VM層只考慮pamp_t 并傳遞這個類型的數(shù)據(jù)即可扔茅,pmap_t 是一個指向struct pmap 是指針已旧,實際上是一個void 指針
  • 機器相關(guān)層:將pmap綁定到一個具體的實現(xiàn),處理底層敬愛個的各種細節(jié)

MachZone

Mach(以及XNU)Zone的概念相當于Linux的內(nèi)存緩存(memory cache)和Windows 的Pool召娜。Zone 是一種內(nèi)存區(qū)域运褪,用于快速分配和是否頻繁使用的固定大小的對象。Zone的API是內(nèi)核內(nèi)部使用的萤晴,在用戶態(tài)不能訪問。Mach中Zone的使用非常廣泛胁后。

Mach Zone 的結(jié)構(gòu)

所有的zone 內(nèi)存實際上都是在調(diào)用zinit( )時預(yù)先分配好的(zinit( )通過底層內(nèi)存分配器kernel_memory_allocate( )分配內(nèi)存)zalloc( )實際上是對REMOVE_FROM_ZONE 宏的封裝店读,作用是返回zone的空閑列表中的下一個元素(如果zone已滿,則調(diào)用kernel_memory_allocate( )分配這個zone在定義的alloc_size字節(jié))屯断。zfree( ) 使用的是相反功能的宏 ADD_TO_ZONE。這兩個函數(shù)都會執(zhí)行合理數(shù)量的參數(shù)檢查趴久,不過這些檢查幫助不大:過去zone分配相關(guān)的bug已經(jīng)導(dǎo)致了數(shù)據(jù)可以被黑客利用的內(nèi)存損壞灭忠。zalloc( ) 最重要的客戶是內(nèi)核中的kalloc( )弛作,這個函數(shù)從kalloc.*系列zone中分配內(nèi)存。BSD的mcache機制也會從自己的zone中分配內(nèi)存。BSD內(nèi)核zone也是如此诸尽,BSD內(nèi)核zone直接構(gòu)建與Mach的zone之上穿肄。

引導(dǎo)期間的zone 設(shè)置

內(nèi)核引導(dǎo)時,vm_mem_bootstrap( )通過兩個調(diào)用設(shè)置zone:

  • zone_bootstrap:設(shè)置主zone(“zones”)脑溢,所有其他的zone數(shù)據(jù)都保存在這里面
  • zone_init:初始化zone子系統(tǒng)的鎖和頁面(使用zone_page_init( ))
zone 垃圾回收

如果系統(tǒng)內(nèi)存不足顶吮,zone可能會進行垃圾回收搏恤。垃圾回收是通過consider_zone_gc( ) 函數(shù)進行的熟空,這個函數(shù)被 cm_pageout_garbage_collect 線程調(diào)用。consider_zone_gc( ) 可能會在以下某種情況中調(diào)用zone垃圾回收(zone_gc):

  • zfree( ) 已經(jīng)釋放了zone中一個超過一個頁面大小的元素俏扩,而且系統(tǒng)的vm_pool低
  • 距離上一次zone_gc 運行已經(jīng)有一段時間了录淡,這個時間由zone_gc_tie_throttle 指定的
  • 系統(tǒng)在休眠,而且調(diào)用了hibernate_flush_memory( )
    垃圾回收是一個兩趟的過程彬檀,首先系統(tǒng)先掃描所有的zone(跳過標記為不可回收的zone)诽偷,檢查這些zone的空閑列表报慕,判斷哪些對象是可以回收的飞苇。在第二趟中,將這些對象轉(zhuǎn)換為頁面:和非空閑對象共享一個頁面的對象不能被釋放忿等,只有頁面全部空閑的對象才能被釋放娃闲。最后卷哩,當判定好了可以釋放的頁面之后冷溶,通過kmem_free( )釋放。
zone 調(diào)試

zone是可以通過以下幾種發(fā)那個是進行調(diào)試的:

  • 編譯時配置CONFIG_ZLEAKS:配置完CONFIG_ZLEAKS后,繪制每個struct zone 中多分配一些數(shù)據(jù)用于檢查內(nèi)存泄露基协。
  • 開關(guān)zone元素檢查:通過-zc引導(dǎo)參數(shù)
  • 開關(guān)zone污染:通過-zp引導(dǎo)參數(shù)
  • 在每一個任務(wù)中保存zone信息:通過-zinfop引導(dǎo)參數(shù)
  • 指定zone日志引導(dǎo)參數(shù):通過zlog參數(shù)指定要記錄日志的zone的準確名字惋鸥,通過zrecs指定日志中要保存的記錄數(shù)目(最多不超過8000)

內(nèi)核內(nèi)存分配器

當內(nèi)核代碼真的需要分配內(nèi)存時亭畜,特別是在自己的vm_map(即kernel_map)中分配內(nèi)存時,就需要實際的分配函數(shù)了,內(nèi)核的分配函數(shù)負責分配虛擬內(nèi)存聘芜,并且做好后備物理內(nèi)存頁面的映射。下圖是XNU中豐富的分配層次架構(gòu):

kernel_memory_allocate( )

所有的內(nèi)核分配(除了連續(xù)物理內(nèi)存的分配)的路徑最終都會到達一個函數(shù),那就是kernel_memory_allocate( )嗅战。這個函數(shù)執(zhí)行實際的內(nèi)存分配疟呐,同時對vm_map和pmap進行操作珊泳。
實際的物理存在分配是通過查看兩個空閑列表中的一個進行的:一個列表是每一個處理器自有的空閑列表晓褪,另一個列表是低內(nèi)存空閑列表。后面這張情況比較罕見好港,只有要求非常特殊的物理內(nèi)存區(qū)域(小于16MB的內(nèi)存區(qū)域)時才需要录择。vm_page_grablo( ) 函數(shù)調(diào)用 cpm_allocate( ),cmp_allocate( )函數(shù)直接從空閑列表中竊取頁面尊剔,從而分配連續(xù)的物理內(nèi)存京痢。

kmem_alloc( ) 系列函數(shù)

Mach 中最常用的內(nèi)存分配器就是kmem_alloc( ) 系列函數(shù)提供的分配器甩十,都是對kernel_memory_allocate( )的封裝

kmem_akkic系列函數(shù)都采用了同樣的原型臣淤,接受三個參數(shù)按厘,分別是map、一個地址指針的輸入輸出參數(shù)以及一個表示大小的參數(shù)草描。這些參數(shù)傳入的map參數(shù)基本上都是kernel_map vm_map逛绵,除非要求的是可分頁的內(nèi)存。
還有一些是構(gòu)建于kernel_memory_allocate( )的kmem_alloc_*函數(shù)。這些函數(shù)包括:

  • kmem_alloc_contig( ):用于分配連續(xù)的物理內(nèi)存(通過cmp_allocte( ))實現(xiàn)
  • **kmem_alloc_pageable( )( 通過cm_map_enter( ) 實現(xiàn)):分配非聯(lián)動的內(nèi)存,非聯(lián)動的內(nèi)存可以在沒有任何警告的情況下都會被交換出去
  • kmem_alloc_pages( ):可以用于在已有對象中分配新的頁鲤孵,這個函數(shù)是對vm_page_alloc( )的封裝(vm_page_alloc( )本本身是對kernel_memory_allocate( )中調(diào)用的vm_page_grab( )/vm_page_insert( )的封裝)

kmem_alloc( )開銷非常大,主要是因為需要后備物理頁面的支持:底層調(diào)用的kernel_memory_allocate( ) 可能會永久阻塞。更多情況下桑滩,使用的是更快的alloc( )(這個分配器是基于更搞笑的zone機制實現(xiàn)的)

kalloc

一旦Mach中的zone都初始化之后胁澳,就可以用于快速的內(nèi)核內(nèi)部內(nèi)寸分配了,這些內(nèi)存分配是由 kalloc_( )系列函數(shù)完成的。這些函數(shù)從功能上等同于用戶態(tài)的 maclloc( ) 。
kalloc函數(shù)是XNU中使用最為廣泛的內(nèi)存分配器,有很多函數(shù)封裝了kalloc幔嗦,其中包括:

  • IOKit 的 IOMalloc:直接封裝了kalloc( )汇恤,還調(diào)用了IOStatisticsAlloc 宏,用于記錄內(nèi)存分配
  • Libkern的kern_os_malloc:直接封裝了kalloc( )风皿,會在分配的內(nèi)存塊之前追加上這個內(nèi)存的大小。new 操作符就是對這個函數(shù)的封裝炊苫。
  • BSD的_MALLOC:用于BSD層的各種分配,也會在分配的內(nèi)存塊之前追加上這個內(nèi)存塊的大小
OSMalloc

Mach 還提供了另一組內(nèi)存分配函數(shù):OSMalloc。OSMalloc 中的關(guān)鍵概念就是標簽,標簽是一個透明的類型磺芭,必須首先分配放棒。調(diào)用者持有了標簽之后损肛,就可以將這個標簽傳入任何一個OSMalloc的函數(shù),那么OSMalloc 通過kmem_alloc_pageable 分配內(nèi)存仙辟。否則戴尸,通過kalloc( )從聯(lián)動內(nèi)存中分配內(nèi)存。標簽本身保存在一個標簽的鏈表中,每一個標簽都有一個引用計數(shù)。分配內(nèi)存會增加這個標簽的引用計數(shù)峭咒。

Mach 分頁器

進程的內(nèi)存需求早晚會超過可用的RAM顽决,系統(tǒng)必須有一種方法能夠?qū)⒉换顒拥捻撁鎮(zhèn)浞萜饋聿⑶覐腞AM中刪除赋访,騰出更多的RAM給活動的頁面使用旋炒,至少暫時能夠滿足活動頁面的需求鼎兽。在其他操作系統(tǒng)中,這個工作專門是由專門的內(nèi)核線程完成的。在Mach 中,這些專門的任務(wù)稱為分頁器(pager)厚宰,分頁器可以是內(nèi)核線程,設(shè)置建議是外部的用戶態(tài)(甚至遠程)服務(wù)程序。
Mach分頁器是一個內(nèi)存管理器,負責將虛擬內(nèi)存?zhèn)浞莸侥硞€特定類型的后備存儲中。當內(nèi)存容量不足,內(nèi)存頁面需要被交換出內(nèi)存是,后備存儲保存內(nèi)存頁面的內(nèi)容:當換出的內(nèi)存頁面需要被使用時,將內(nèi)存的頁面恢復(fù)到RAM中巨双。只有“臟”頁面才需要進行上述的換出和換入慢宗,因為“臟”頁面是在內(nèi)存中修改過的頁面贱田,要從RAM中剔除時必須保存到磁盤中防止數(shù)據(jù)丟失蔬墩。
要注意的是樟插,這里提到的分頁器僅僅實現(xiàn)了各自負責的內(nèi)存對象的分頁操作鸵熟,這些分頁器不會控制系統(tǒng)的分頁策略煮盼。分頁策略是有vm_pageout 守護線程負責的报破。

分頁器的類型

iOS 和 OS X 中XNU 包含的分頁器種類都是一樣的盹靴。下表是XNU中的內(nèi)存分頁器的多種類型:

內(nèi)存分頁器 用途
Default 分頁器(默認) 匿名內(nèi)存
VNode 分頁器 內(nèi)存映射的文件
Device 分頁器 設(shè)置后援的I/O
Swapfile 分頁器 處理特定的swapfile 映射的嘗試控漠,防止通過內(nèi)存映射讀取交換文件的數(shù)據(jù)
Apple-protected 分頁器 蘋果特有的擴展:對內(nèi)存(二進制文件所在的內(nèi)存)加密提供支持
Freezer(僅用于iOS) iOS 特有的擴展毙驯,支持“冷凍”進程

分頁策略管理

Pageout 守護程序

pageout 守護程序其實不是一個真的守護程序,而是一個線程。而且不是一般的線程:當kernel_bootstarp_thread( ) 完成內(nèi)核初始化工作并且沒有其他事情可做時,就調(diào)用vm_pageout( ) 成為了pageour 守護程序, vm_pageout( ) 永遠不返回。這個線程管理頁面交換的策略哄酝,判斷哪些頁面需要寫回到其后備存儲直晨。

  • vm_pageout線程
    vm_pageout( ) 函數(shù)講kernel_bootstrap_thread 線程轉(zhuǎn)變?yōu)閜ageout 守護程序的止,這個函數(shù)實際上重新設(shè)置了這個線程氓润。設(shè)置完成后崩溪,調(diào)用vm_pageout_continute( )乳幸,這個函數(shù)周期性地喚醒并執(zhí)行vm_page_scan( )姿染,維護4個頁面表(稱為頁面隊列)盾戴。系統(tǒng)中的每一個vm_page 都通過pageq字段綁定這4個隊列中的一個:

  • vm_page_queue_active:最近活躍且駐留在內(nèi)存中的頁面

  • vm_page_queue_inactive:最近不活躍的頁面,因此這些頁面是頁面換出的備選頁面。根據(jù)這些頁面的使用情況,可能會被換出极祸,也可能會被重新激活

  • vm_page_queue_free:空閑頁面表汰规。這些頁面曾經(jīng)是非活躍的頁面色解,但是被清理出去了(頁面換出)

  • vm_page_queue_speculative:這些頁面是通過預(yù)讀策略投機映射的頁面蝌矛,這些頁面是不活躍的璃赡,但是很可能很快會變?yōu)榛钴S頁面

  • vm_pageout iothread線程
    內(nèi)部和外部iothread 線程各自檢查一個vm_pageout_queue_t,這兩個vm_page_queue_t 都是由vm_pageout( )初始化的。vm_pageout_queue_internal 專門用于內(nèi)部的VM對象(即那些內(nèi)核創(chuàng)建的VM對象窍箍,又默認分頁器維護祷蝌,internel 標準設(shè)置為true),vm_pageout_queue_external 用于其他所有的VM對象
    這兩個線程都使用了同一個線程函數(shù)vm_pageout_iothread_continue( ) 只不過操作的是不同的隊列。這個函數(shù)(嚴格地說是一個續(xù)體)遍歷自己的隊列,出隊隊列中的每一個頁面邪蛔,獲得其對應(yīng)的分頁器(通過vm_object 引用)污抬,然后調(diào)用器分頁器的memory_object_data_return( ) 函數(shù)多柑。這種方式可以使得pageout 線程和實際的分頁操作實現(xiàn)解耦,分頁器操作是由分頁器單獨負責的兔毒。

  • 垃圾回收線程
    垃圾回收線程(vm_pageout_garbage_collect( ))偶爾會被vm_pageout_scan( ) 通過其續(xù)體喚醒。垃圾回收機制線程處理4個方面的垃圾回收工作:

  • srack_collect( ):內(nèi)核棧中的頁面

  • consider_machine_collect( ):回收機器相關(guān)的頁面

  • consider_buffer_cache_collect( ):如果確定定義了這個函數(shù)則調(diào)用這個函數(shù)钦睡。調(diào)用這通過vm_set_buffer_cleanup_callout( ) 定義這個函數(shù)。BSD 層在bufinit( ) 函數(shù)中注冊了buffer_cache_gc( ) 函數(shù)

  • consider_zone_gc( ):zone 相關(guān)的垃圾回收

處理頁錯誤

vm_pageout( ) 守護程序處理的只是交換的一個方向啦撮,從物理內(nèi)存換出到后備存儲骄崩。而另外一個方向是頁面換入,則是發(fā)生在頁面錯誤的時候處理的蔚润。這個邏輯非常復(fù)雜挫以,簡化為一下步驟:

  • 如果陷阱的原因是頁錯誤,那么機器級別的線程處理程序調(diào)用vm_fault( )
  • vm_fault( ) 函數(shù)調(diào)用 vm_pageout_fault( )處理實際發(fā)生錯誤的頁面殴蹄,并且從后備存儲中將這個頁面返回
  • PMAP_ENTER( ) 將頁面插入任務(wù)的pmap

頁錯誤有很多種工腋,上述只是其中一種,其他類型的也錯誤還包括:

  • 非法訪問:訪問應(yīng)該沒有映射到進程地址空間(即任務(wù)的vm_map)的地址沐绒。解引用應(yīng)該野指針時通常會發(fā)生這種錯誤括尸。發(fā)生這種錯誤時進程會收到SIGSEGV信號
  • 頁面保護錯誤:訪問應(yīng)該映射的地址僧家,但是頁面的保護掩碼拒絕請求的訪問
  • 寫時復(fù)制(copy-on-write):頁面可以被標記可讀爹谭,因此如果任務(wù)試圖寫入頁面時,會捕捉到這個錯誤运沦,在重新嘗試寫入操作之前可以將這個頁面復(fù)制出來
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末矫限,一起剝皮案震驚了整個濱河市孽鸡,隨后出現(xiàn)的幾起案子搬泥,更是在濱河造成了極大的恐慌班套,老刑警劉巖猿规,帶你破解...
    沈念sama閱讀 206,968評論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件猬仁,死亡現(xiàn)場離奇詭異的烁,居然都是意外死亡襟雷,警方通過查閱死者的電腦和手機卓缰,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,601評論 2 382
  • 文/潘曉璐 我一進店門偿乖,熙熙樓的掌柜王于貴愁眉苦臉地迎上來娃弓,“玉大人侠坎,你說我怎么就攤上這事∪苟埽” “怎么了实胸?”我有些...
    開封第一講書人閱讀 153,220評論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長闷煤。 經(jīng)常有香客問我童芹,道長,這世上最難降的妖魔是什么鲤拿? 我笑而不...
    開封第一講書人閱讀 55,416評論 1 279
  • 正文 為了忘掉前任假褪,我火速辦了婚禮,結(jié)果婚禮上近顷,老公的妹妹穿的比我還像新娘生音。我一直安慰自己,他們只是感情好窒升,可當我...
    茶點故事閱讀 64,425評論 5 374
  • 文/花漫 我一把揭開白布缀遍。 她就那樣靜靜地躺著,像睡著了一般饱须。 火紅的嫁衣襯著肌膚如雪域醇。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,144評論 1 285
  • 那天,我揣著相機與錄音譬挚,去河邊找鬼锅铅。 笑死,一個胖子當著我的面吹牛减宣,可吹牛的內(nèi)容都是我干的盐须。 我是一名探鬼主播,決...
    沈念sama閱讀 38,432評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼漆腌,長吁一口氣:“原來是場噩夢啊……” “哼贼邓!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起闷尿,我...
    開封第一講書人閱讀 37,088評論 0 261
  • 序言:老撾萬榮一對情侶失蹤塑径,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后悠砚,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體晓勇,經(jīng)...
    沈念sama閱讀 43,586評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,028評論 2 325
  • 正文 我和宋清朗相戀三年灌旧,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片绰筛。...
    茶點故事閱讀 38,137評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡枢泰,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出铝噩,到底是詐尸還是另有隱情衡蚂,我是刑警寧澤,帶...
    沈念sama閱讀 33,783評論 4 324
  • 正文 年R本政府宣布骏庸,位于F島的核電站毛甲,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏具被。R本人自食惡果不足惜玻募,卻給世界環(huán)境...
    茶點故事閱讀 39,343評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望一姿。 院中可真熱鬧七咧,春花似錦、人聲如沸叮叹。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,333評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽蛉顽。三九已至蝗砾,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背悼粮。 一陣腳步聲響...
    開封第一講書人閱讀 31,559評論 1 262
  • 我被黑心中介騙來泰國打工拇泣, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人矮锈。 一個月前我還...
    沈念sama閱讀 45,595評論 2 355
  • 正文 我出身青樓霉翔,卻偏偏與公主長得像,于是被迫代替她去往敵國和親苞笨。 傳聞我的和親對象是個殘疾皇子债朵,可洞房花燭夜當晚...
    茶點故事閱讀 42,901評論 2 345

推薦閱讀更多精彩內(nèi)容