精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

Linux內(nèi)核的頁面錯誤:原因與解決方案

開發(fā) 前端
頁異常對系統(tǒng)性能有著顯著的影響,尤其是硬缺頁。由于硬缺頁需要從磁盤讀取數(shù)據(jù)到內(nèi)存,而磁盤 I/O 的速度遠遠慢于內(nèi)存訪問速度,頻繁的硬缺頁會導致系統(tǒng)性能大幅下降 。

當程序訪問虛擬內(nèi)存中的一個頁面時,如果該頁面當前不在物理內(nèi)存中,就會觸發(fā)一個稱為"page fault"(頁異常)的異常。操作系統(tǒng)需要處理這個異常,并將所需頁面從磁盤加載到內(nèi)存中。實現(xiàn)虛存管理的一個關(guān)鍵是page fault異常處理,其過程中主要涉及到函數(shù) — do_pgfault的具體實現(xiàn)。

比如,在程序的執(zhí)行過程中由于某種原因(頁框不存在/寫只讀頁等)而使 CPU 無法最終訪問到相應的物理內(nèi)存單元,即無法完成從虛擬地址到物理地址映射時,CPU 會產(chǎn)生一次頁訪問異常,從而需要進行相應的頁訪問異常的中斷服務(wù)例程。這個頁訪問異常處理的時機被操作系統(tǒng)充分利用來完成虛存管理,即實現(xiàn)“按需調(diào)頁”/“頁換入換出”處理的執(zhí)行時機。當相關(guān)處理完成后,頁訪問異常服務(wù)例程會返回到產(chǎn)生異常的指令處重新執(zhí)行,使得應用軟件可以繼續(xù)正常運行下去。

一、內(nèi)存管理前奏:虛擬內(nèi)存與MMU

在深入探討頁異常之前,先來了解一下 Linux 內(nèi)存管理的基礎(chǔ)架構(gòu)。在 Linux 系統(tǒng)中,進程并不直接訪問物理內(nèi)存,而是通過內(nèi)存管理單元(Memory Management Unit,MMU)來管理虛擬地址與物理地址的映射關(guān)系。

想象一下,你正在玩一款角色扮演游戲,每個角色都有自己獨立的背包(虛擬地址空間),背包里的物品位置(虛擬地址)與實際倉庫(物理內(nèi)存)中的存儲位置是通過游戲管理員(MMU)來協(xié)調(diào)的。這樣,每個角色都覺得自己的背包很大,有足夠的空間放置物品,而實際上倉庫的空間是有限的。這就是虛擬內(nèi)存的作用,它讓進程以為自己擁有很大的連續(xù)內(nèi)存空間,而不必關(guān)心物理內(nèi)存的實際布局和大小限制。

什么是虛擬內(nèi)存?

簡單地說是指程序員或CPU“看到”的內(nèi)存。但有幾點需要注意:

  • 虛擬內(nèi)存單元不一定有實際的物理內(nèi)存單元對應,即實際的物理內(nèi)存單元可能不存在;
  • 如果虛擬內(nèi)存單元對應有實際的物理內(nèi)存單元,那二者的地址一般是不相等的;
  • 通過操作系統(tǒng)實現(xiàn)的某種內(nèi)存映射可建立虛擬內(nèi)存與物理內(nèi)存的對應關(guān)系,使得程序員或CPU訪問的虛擬內(nèi)存地址會自動轉(zhuǎn)換為一個物理內(nèi)存地址。

那么這個“虛擬”的作用或意義在哪里體現(xiàn)呢?在操作系統(tǒng)中,虛擬內(nèi)存其實包含多個虛擬層次,在不同的層次體現(xiàn)了不同的作用。首先,在有了分頁機制后,程序員或CPU“看到”的地址已經(jīng)不是實際的物理地址了,這已經(jīng)有一層虛擬化,我們可簡稱為內(nèi)存地址虛擬化。有了內(nèi)存地址虛擬化,我們就可以通過設(shè)置頁表項來限定軟件運行時的訪問空間,確保軟件運行不越界,完成內(nèi)存訪問保護的功能。

虛擬內(nèi)存地址空間的引入,不僅解決了物理內(nèi)存不足的問題,還提供了內(nèi)存保護和進程隔離的功能。每個進程都有自己獨立的虛擬地址空間,彼此之間互不干擾,就像不同的游戲角色在各自的背包里操作物品,不會影響到其他角色的背包。這樣,一個進程的內(nèi)存訪問錯誤不會導致整個系統(tǒng)崩潰,大大提高了系統(tǒng)的穩(wěn)定性和安全性。

通過 MMU 的映射,虛擬地址被轉(zhuǎn)換為物理地址,這個過程就像是游戲管理員根據(jù)角色背包里的物品位置信息,到實際倉庫中找到對應的物品。MMU 通過維護頁表(Page Table)來記錄虛擬地址與物理地址的映射關(guān)系,頁表就像是一本詳細的地址轉(zhuǎn)換字典,MMU 根據(jù)虛擬地址在頁表中查找對應的物理地址。

在 32 位的 Linux 系統(tǒng)中,虛擬地址空間通常為 4GB,其中一部分用于用戶空間,另一部分用于內(nèi)核空間。用戶空間的進程只能訪問自己的虛擬地址空間,無法直接訪問內(nèi)核空間,這種隔離機制有效地保護了內(nèi)核的安全,防止用戶進程的非法操作對內(nèi)核造成破壞 。例如,普通用戶在自己的權(quán)限范圍內(nèi)進行文件操作,無法直接訪問系統(tǒng)核心文件,保障了系統(tǒng)的穩(wěn)定性。

虛擬內(nèi)存與 MMU 的這種映射機制,為 Linux 系統(tǒng)的內(nèi)存管理奠定了堅實的基礎(chǔ),同時也為頁異常的發(fā)生埋下了伏筆,當進程訪問的虛擬地址在頁表中找不到對應的物理地址映射時,頁異常就會登場 。

二、數(shù)據(jù)結(jié)構(gòu)與函數(shù)

首先是初始化過程。參考ucore總控函數(shù)init的代碼,可以看到在調(diào)用完成虛擬內(nèi)存初始化的vmm_init函數(shù)之前,需要首先調(diào)用pmm_init函數(shù)完成物理內(nèi)存的管理,這也是我們lab2已經(jīng)完成的內(nèi)容。接著是執(zhí)行中斷和異常相關(guān)的初始化工作,即調(diào)用pic_init函數(shù)和idt_init函數(shù)等,這些工作與lab1的中斷異常初始化工作的內(nèi)容是相同的。

在調(diào)用完idt_init函數(shù)之后,將進一步調(diào)用三個lab3中才有的新函數(shù)vmm_init、ide_init和swap_init。這三個函數(shù)涉及了本次實驗中的兩個練習。第一個函數(shù)vmm_init是檢查我們的練習1是否正確實現(xiàn)了。為了表述不在物理內(nèi)存中的“合法”虛擬頁,需要有數(shù)據(jù)結(jié)構(gòu)來描述這樣的頁,為此ucore建立了mm_struct和vma_struct數(shù)據(jù)結(jié)構(gòu)(接下來的小節(jié)中有進一步詳細描述),假定我們已經(jīng)描述好了這樣的“合法”虛擬頁,當ucore訪問這些“合法”虛擬頁時,會由于沒有虛實地址映射而產(chǎn)生頁訪問異常。如果我們正確實現(xiàn)了練習1,則do_pgfault函數(shù)會申請一個空閑物理頁,并建立好虛實映射關(guān)系,從而使得這樣的“合法”虛擬頁有實際的物理頁幀對應。這樣練習1就算完成了。

ide_init和swap_init是為練習2準備的。由于頁面置換算法的實現(xiàn)存在對硬盤數(shù)據(jù)塊的讀寫,所以ide_init就是完成對用于頁換入換出的硬盤(簡稱swap硬盤)的初始化工作。完成ide_init函數(shù)后,ucore就可以對這個swap硬盤進行讀寫操作了。swap_init函數(shù)首先建立swap_manager,swap_manager是完成頁面替換過程的主要功能模塊,其中包含了頁面置換算法的實現(xiàn)(具體內(nèi)容可參考5小節(jié))。

然后會進一步調(diào)用執(zhí)行check_swap函數(shù)在內(nèi)核中分配一些頁,模擬對這些頁的訪問,這會產(chǎn)生頁訪問異常。如果我們正確實現(xiàn)了練習2,就可通過do_pgfault來調(diào)用swap_map_swappable函數(shù)來查詢這些頁的訪問情況并間接調(diào)用實現(xiàn)頁面置換算法的相關(guān)函數(shù),把“不常用”的頁換出到磁盤上。

ucore在實現(xiàn)上述技術(shù)時,需要解決三個關(guān)鍵問題:

  • 當程序運行中訪問內(nèi)存產(chǎn)生page
    fault異常時,如何判定這個引起異常的虛擬地址內(nèi)存訪問是越界、寫只讀頁的“非法地址”訪問還是由于數(shù)據(jù)被臨時換出到磁盤上或還沒有分配內(nèi)存的“合法地址”訪問?
  • 何時進行請求調(diào)頁/頁換入換出處理?
  • 如何在現(xiàn)有ucore的基礎(chǔ)上實現(xiàn)頁替換算法?

接下來將進一步分析完成lab3主要注意的關(guān)鍵問題和涉及的關(guān)鍵數(shù)據(jù)結(jié)構(gòu)。

對于第一個問題的出現(xiàn),在于實驗二中有關(guān)內(nèi)存的數(shù)據(jù)結(jié)構(gòu)和相關(guān)操作都是直接針對實際存在的資源—物理內(nèi)存空間的管理,沒有從一般應用程序?qū)?nèi)存的“需求”考慮,即需要有相關(guān)的數(shù)據(jù)結(jié)構(gòu)和操作來體現(xiàn)一般應用程序?qū)μ摂M內(nèi)存的“需求”。一般應用程序的對虛擬內(nèi)存的“需求”與物理內(nèi)存空間的“供給”沒有直接的對應關(guān)系,ucore是通過page fault異常處理來間接完成這二者之間的銜接。

page_fault函數(shù)不知道哪些是“合法”的虛擬頁,原因是ucore還缺少一定的數(shù)據(jù)結(jié)構(gòu)來描述這種不在物理內(nèi)存中的“合法”虛擬頁。為此ucore通過建立mm_struct和vma_struct數(shù)據(jù)結(jié)構(gòu),描述了ucore模擬應用程序運行所需的合法內(nèi)存空間。當訪問內(nèi)存產(chǎn)生page fault異常時,可獲得訪問的內(nèi)存的方式(讀或?qū)懀┮约熬唧w的虛擬內(nèi)存地址,這樣ucore就可以查詢此地址,看是否屬于vma_struct數(shù)據(jù)結(jié)構(gòu)中描述的合法地址范圍中,如果在,則可根據(jù)具體情況進行請求調(diào)頁/頁換入換出處理(這就是練習2涉及的部分);如果不在,則報錯。mm_struct和vma_struct數(shù)據(jù)結(jié)構(gòu)結(jié)合頁表表示虛擬地址空間和物理地址空間的示意圖如下所示:

圖片圖片

在ucore中描述應用程序?qū)μ摂M內(nèi)存“需求”的數(shù)據(jù)結(jié)構(gòu)是vma_struct(定義在vmm.h中),以及針對vma_struct的函數(shù)操作。這里把一個vma_struct結(jié)構(gòu)的變量簡稱為vma變量。vma_struct的定義如下:

struct vma_struct {
    // the set of vma using the same PDT
    struct mm_struct *vm_mm;
    uintptr_t vm_start; // start addr of vma
    uintptr_t vm_end; // end addr of vma
    uint32_t vm_flags; // flags of vma
    //linear list link which sorted by start addr of vma
    list_entry_t list_link;
};

vm_start和vm_end描述了一個連續(xù)地址的虛擬內(nèi)存空間的起始位置和結(jié)束位置,這兩個值都應該是PGSIZE 對齊的,而且描述的是一個合理的地址空間范圍(即嚴格確保 vm_start < vm_end的關(guān)系);list_link是一個雙向鏈表,按照從小到大的順序把一系列用vma_struct表示的虛擬內(nèi)存空間鏈接起來,并且還要求這些鏈起來的vma_struct應該是不相交的,即vma之間的地址空間無交集;vm_flags表示了這個虛擬內(nèi)存空間的屬性,目前的屬性包括:

#define VM_READ 0x00000001 //只讀
#define VM_WRITE 0x00000002 //可讀寫
#define VM_EXEC 0x00000004 //可執(zhí)行

vm_mm是一個指針,指向一個比vma_struct更高的抽象層次的數(shù)據(jù)結(jié)構(gòu)mm_struct,這里把一個mm_struct結(jié)構(gòu)的變量簡稱為mm變量。這個數(shù)據(jù)結(jié)構(gòu)表示了包含所有虛擬內(nèi)存空間的共同屬性,具體定義如下:

struct mm_struct {
    // linear list link which sorted by start addr of vma
    list_entry_t mmap_list;
    // current accessed vma, used for speed purpose
    struct vma_struct *mmap_cache;
    pde_t *pgdir; // the PDT of these vma
    int map_count; // the count of these vma
    void *sm_priv; // the private data for swap manager
};

mmap_list是雙向鏈表頭,鏈接了所有屬于同一頁目錄表的虛擬內(nèi)存空間,mmap_cache是指向當前正在使用的虛擬內(nèi)存空間,由于操作系統(tǒng)執(zhí)行的“局部性”原理,當前正在用到的虛擬內(nèi)存空間在接下來的操作中可能還會用到,這時就不需要查鏈表,而是直接使用此指針就可找到下一次要用到的虛擬內(nèi)存空間。由于mmap_cache 的引入,可使得 mm_struct 數(shù)據(jù)結(jié)構(gòu)的查詢加速 30% 以上。pgdir

所指向的就是 mm_struct數(shù)據(jù)結(jié)構(gòu)所維護的頁表。通過訪問pgdir可以查找某虛擬地址對應的頁表項是否存在以及頁表項的屬性等。map_count記錄mmap_list 里面鏈接的 vma_struct的個數(shù)。sm_priv指向用來鏈接記錄頁訪問情況的鏈表頭,這建立了mm_struct和后續(xù)要講到的swap_manager之間的聯(lián)系。

涉及vma_struct的操作函數(shù)也比較簡單,主要包括三個:

  • vma_create—創(chuàng)建vma
  • insert_vma_struct—插入一個vma
  • find_vma—查詢vma。

vma_create函數(shù)根據(jù)輸入?yún)?shù)vm_start、vm_end、vm_flags來創(chuàng)建并初始化描述一個虛擬內(nèi)存空間的vma_struct結(jié)構(gòu)變量。insert_vma_struct函數(shù)完成把一個vma變量按照其空間位置[vma->vm_start,vma->vm_end]從小到大的順序插入到所屬的mm變量中的mmap_list雙向鏈表中。find_vma根據(jù)輸入?yún)?shù)addr和mm變量,查找在mm變量中的mmap_list雙向鏈表中某個vma包含此addr,即vma->vm_start<=addr end。這三個函數(shù)與后續(xù)講到的page fault異常處理有緊密聯(lián)系。

涉及mm_struct的操作函數(shù)比較簡單,只有mm_create和mm_destroy兩個函數(shù),從字面意思就可以看出是是完成mm_struct結(jié)構(gòu)的變量創(chuàng)建和刪除。在mm_create中用kmalloc分配了一塊空間,所以在mm_destroy中也要對應進行釋放。在ucore運行過程中,會產(chǎn)生描述虛擬內(nèi)存空間的vma_struct結(jié)構(gòu),所以在mm_destroy中也要進對這些mmap_list中的vma進行釋放。

三、Page Fault異常處理

當進程訪問它的虛擬地址空間中的 PAGE 時,如果這個 PAGE 目前還不在物理內(nèi)存中,此時 CPU 就像一個找不到文件的辦事員,無法繼續(xù)工作。Linux 會立即產(chǎn)生一個 hard page fault 中斷,這就像是辦事員向上級報告文件缺失的情況 。

在這個過程中,系統(tǒng)需要從慢速設(shè)備(如磁盤)將對應的數(shù)據(jù) PAGE 讀入物理內(nèi)存,就好比從倉庫(磁盤)中找到文件并取出來。然后,建立物理內(nèi)存地址與虛擬地址空間 PAGE 的映射關(guān)系,這一步就像是給文件貼上標簽,標明它在虛擬地址空間中的位置。只有完成這些步驟后,進程才能訪問這部分虛擬地址空間的內(nèi)存,辦事員才能繼續(xù)處理文件。

產(chǎn)生頁訪問異常的原因主要有:

  • 目標頁幀不存在(頁表項全為0,即該線性地址與物理地址尚未建立映射或者已經(jīng)撤銷);
  • 相應的物理頁幀不在內(nèi)存中(頁表項非空,但Present標志位=0,比如在swap分區(qū)或磁盤文件上),這在本次實驗中會出現(xiàn),我們將在下面介紹換頁機制實現(xiàn)時進一步講解如何處理;
  • 不滿足訪問權(quán)限(此時頁表項P標志=1,但低權(quán)限的程序試圖訪問高權(quán)限的地址空間,或者有程序試圖寫只讀頁面)

當出現(xiàn)上面情況之一,那么就會產(chǎn)生頁面page fault(#PF)異常。CPU會把產(chǎn)生異常的線性地址存儲在CR2中,并且把表示頁訪問異常類型的值(簡稱頁訪問異常錯誤碼,errorCode)保存在中斷棧中。

頁訪問異常錯誤碼有32位。位0為1表示對應物理頁不存在;位1為1表示寫異常(比如寫了只讀頁;位2為1表示訪問權(quán)限異常(比如用戶態(tài)程序訪問內(nèi)核空間的數(shù)據(jù))
CR2是頁故障線性地址寄存器,保存最后一次出現(xiàn)頁故障的全32位線性地址。CR2用于發(fā)生頁異常時報告出錯信息。當發(fā)生頁異常時,處理器把引起頁異常的線性地址保存在CR2中。操作系統(tǒng)中對應的中斷服務(wù)例程可以檢查CR2的內(nèi)容,從而查出線性地址空間中的哪個頁引起本次異常。

產(chǎn)生頁訪問異常后,CPU硬件和軟件都會做一些事情來應對此事。首先頁訪問異常也是一種異常,所以針對一般異常的硬件處理操作是必須要做的,即CPU在當前內(nèi)核棧保存當前被打斷的程序現(xiàn)場,即依次壓入當前被打斷程序使用的EFLAGS,CS,EIP,errorCode;由于頁訪問異常的中斷號是0xE,CPU把異常中斷號0xE對應的中斷服務(wù)例程的地址(vectors.S中的標號vector14處)加載到CS和EIP寄存器中,開始執(zhí)行中斷服務(wù)例程。這時ucore開始處理異常中斷,首先需要保存硬件沒有保存的寄存器。

在vectors.S中的標號vector14處先把中斷號壓入內(nèi)核棧,然后再在trapentry.S中的標號__alltraps處把DS、ES和其他通用寄存器都壓棧。自此,被打斷的程序執(zhí)行現(xiàn)場(context)被保存在內(nèi)核棧中。接下來,在trap.c的trap函數(shù)開始了中斷服務(wù)例程的處理流程,大致調(diào)用關(guān)系為:

trap—> trap_dispatch—>pgfault_handler—>do_pgfault

在操作系統(tǒng)中,do_pgfault(頁錯誤處理函數(shù))是由內(nèi)核調(diào)用的函數(shù)。當程序訪問一個尚未映射到物理內(nèi)存的頁面時,會觸發(fā)頁錯誤異常。此時,操作系統(tǒng)會捕獲這個異常,并將控制權(quán)轉(zhuǎn)移到do_pgfault函數(shù)中進行處理。

具體的調(diào)用關(guān)系可能因不同的操作系統(tǒng)和架構(gòu)而有所差異,以下是一般情況下的調(diào)用關(guān)系:

  • 當發(fā)生頁錯誤時,CPU會產(chǎn)生一個異常,并將控制權(quán)交給操作系統(tǒng)。
  • 操作系統(tǒng)根據(jù)異常類型確定是否為頁錯誤,并檢查導致頁錯誤的原因。
  • 如果是頁面訪問權(quán)限問題或者缺頁(頁面尚未加載到物理內(nèi)存)等原因引起的頁錯誤,則執(zhí)行相應的處理邏輯。
  • 在處理邏輯中,操作系統(tǒng)可能需要分配物理內(nèi)存來滿足缺頁請求,并將相應的頁面加載到物理內(nèi)存中。
  • 執(zhí)行完必要的處理后,操作系統(tǒng)將重新設(shè)置相關(guān)寄存器和標志位,然后恢復被中斷的進程繼續(xù)執(zhí)行。

總之,do_pgfault函數(shù)作為內(nèi)核提供的一個重要回調(diào)函數(shù),在頁錯誤發(fā)生時負責處理該異常并采取必要措施

產(chǎn)生頁訪問異常后,CPU把引起頁訪問異常的線性地址裝到寄存器CR2中,并給出了出錯碼errorCode,說明了頁訪問異常的類型。ucore OS會把這個值保存在struct trapframe 中tf_err成員變量中。而中斷服務(wù)例程會調(diào)用頁訪問異常處理函數(shù)do_pgfault進行具體處理。這里的頁訪問異常處理是實現(xiàn)按需分頁、頁換入換出機制的關(guān)鍵之處。

ucore中do_pgfault函數(shù)是完成頁訪問異常處理的主要函數(shù),它根據(jù)從CPU的控制寄存器CR2中獲取的頁訪問異常的物理地址以及根據(jù)errorCode的錯誤類型來查找此地址是否在某個VMA的地址范圍內(nèi)以及是否滿足正確的讀寫權(quán)限,如果在此范圍內(nèi)并且權(quán)限也正確,這認為這是一次合法訪問,但沒有建立虛實對應關(guān)系。所以需要分配一個空閑的內(nèi)存頁,并修改頁表完成虛地址到物理地址的映射,刷新TLB,然后調(diào)用iret中斷,返回到產(chǎn)生頁訪問異常的指令處重新執(zhí)行此指令。如果該虛地址不在某VMA范圍內(nèi),則認為是一次非法訪問。

3.1缺頁錯誤的分類處理

我們在前作內(nèi)存尋址中介紹了 CPU 發(fā)展過程中內(nèi)存尋址方式的變化。現(xiàn)代 CPU 都支持分段和分頁的內(nèi)存尋址模式。出于尋址能力的考慮,現(xiàn)代操作系統(tǒng),也順應著都支持段頁式的內(nèi)存管理模式。當然,雖然支持段頁式,但是 Linux 中只啟用了段基址為 0 的段。也就是說,在 Linux 當中,實際起作用的只有分頁模式。

具體來說,分頁模式在邏輯上將虛擬內(nèi)存和物理內(nèi)存同時等分成固定大小的塊。這些塊在虛擬內(nèi)存上稱之為「頁」,而在物理內(nèi)存上稱之為「頁幀」,并交由 CPU 中的 MMU 模塊來負責頁幀和頁之間的映射管理。

引入分頁模式的好處,可以大致概括為兩個方面:

  • 允許虛存空間遠大于實際物理內(nèi)存大小的情況。這是因為,分頁之后,操作系統(tǒng)讀入磁盤的文件時,無需以文件為單位全部讀入,而可以以內(nèi)存頁為單位,分片讀入。同時,考慮到 CPU 不可能一次性需要使用整個內(nèi)存中的數(shù)據(jù),因此可以交由特定的算法,進行內(nèi)存調(diào)度:將長時間不用的頁幀內(nèi)的數(shù)據(jù)暫存到磁盤上。
  • 減少了內(nèi)存碎片的產(chǎn)生。這是因為,引入分頁之后,內(nèi)存的分配管理都是以頁大小(通常是 4KiB,擴展分頁模式下是 4MiB)為單位的;虛擬內(nèi)存中的頁總是對應物理內(nèi)存中實際的頁幀。這樣一來,在虛擬內(nèi)存空間中,頁內(nèi)連續(xù)的內(nèi)存在物理內(nèi)存上也一定是連續(xù)的,不會產(chǎn)生碎片。

當進程在進行一些計算時,CPU 會請求內(nèi)存中存儲的數(shù)據(jù)。在這個請求過程中,CPU 發(fā)出的地址是邏輯地址(虛擬地址),然后交由 CPU 當中的 MMU 單元進行內(nèi)存尋址,找到實際物理內(nèi)存上的內(nèi)容。若是目標虛存空間中的內(nèi)存頁(因為某種原因),在物理內(nèi)存中沒有對應的頁幀,那么 CPU 就無法獲取數(shù)據(jù)。這種情況下,CPU 是無法進行計算的,于是它就會報告一個缺頁錯誤(Page Fault)。

因為 CPU 無法繼續(xù)進行進程請求的計算,并報告了缺頁錯誤,用戶進程必然就中斷了。這樣的中斷稱之為缺頁中斷。在報告 Page Fault 之后,進程會從用戶態(tài)切換到系統(tǒng)態(tài),交由操作系統(tǒng)內(nèi)核的 Page Fault Handler 處理缺頁錯誤。

基本來說,缺頁錯誤可以分為兩類:硬缺頁錯誤(Hard Page Fault)和軟缺頁錯誤(Soft Page Fault)。這里,前者又稱為主要缺頁錯誤(Major Page Fault);后者又稱為次要缺頁錯誤(Minor Page Fault)。當缺頁中斷發(fā)生后,Page Fault Handler 會判斷缺頁的類型,進而處理缺頁錯誤,最終將控制權(quán)交給用戶態(tài)代碼。

若是此時物理內(nèi)存里,已經(jīng)有一個頁幀正是此時 CPU 請求的內(nèi)存頁,那么這是一個軟缺頁錯誤;于是,Page Fault Hander 會指示 MMU 建立相應的頁幀到頁的映射關(guān)系。這一操作的實質(zhì)是進程間共享內(nèi)存——比如動態(tài)庫(共享對象),比如 mmap 的文件。

若是此時物理內(nèi)存中,沒有相應的頁幀,那么這就是一個硬缺頁錯誤;于是 Page Fault Hander 會指示 CPU,從已經(jīng)打開的磁盤文件中讀取相應的內(nèi)容到物理內(nèi)存,而后交由 MMU 建立這份頁幀到頁的映射關(guān)系。

不難發(fā)現(xiàn),軟缺頁錯誤只是在內(nèi)核態(tài)里輕輕地走了一遭,而硬缺頁錯誤則涉及到磁盤 I/O。因此,處理起來,硬缺頁錯誤要比軟缺頁錯誤耗時長得多。這就是為什么我們要求高性能程序必須在對外提供服務(wù)時,盡可能少地發(fā)生硬缺頁錯誤。

除了硬缺頁錯誤和軟缺頁錯誤之外,還有一類缺頁錯誤是因為訪問非法內(nèi)存引起的。前兩類缺頁錯誤中,進程嘗試訪問的虛存地址尚為合法有效的地址,只是對應的物理內(nèi)存頁幀沒有在物理內(nèi)存當中。后者則不然,進程嘗試訪問的虛存地址是非法無效的地址。比如嘗試對 nullptr 解引用,就會訪問地址為 0x0 的虛存地址,這是非法地址。

此時 CPU 報出無效缺頁錯誤(Invalid Page Fault)。操作系統(tǒng)對無效缺頁錯誤的處理各不相同:Windows 會使用異常機制向進程報告;*nix 則會通過向進程發(fā)送 SIGSEGV 信號(11),引發(fā)內(nèi)存轉(zhuǎn)儲。

缺頁中斷會交給PageFaultHandler處理,其根據(jù)缺頁中斷的不同類型會進行不同的處理:

  • Hard Page Fault:也被稱為Major Page Fault,翻譯為硬缺頁錯誤/主要缺頁錯誤,這時物理內(nèi)存中沒有對應的頁幀,需要CPU打開磁盤設(shè)備讀取到物理內(nèi)存中,再讓MMU建立VA和PA的映射。
  • Soft Page Fault:也被稱為Minor Page Fault,翻譯為軟缺頁錯誤/次要缺頁錯誤,這時物理內(nèi)存中是存在對應頁幀的,只不過可能是其他進程調(diào)入的,發(fā)出缺頁異常的進程不知道而已,此時MMU只需要建立映射即可,無需從磁盤讀取寫入內(nèi)存,一般出現(xiàn)在多進程共享內(nèi)存區(qū)域。
  • Invalid Page Fault:翻譯為無效缺頁錯誤,比如進程訪問的內(nèi)存地址越界訪問,又比如對空指針解引用內(nèi)核就會報segment fault錯誤中斷進程直接掛掉。

圖片

3.2缺頁錯誤出現(xiàn)的原因

(1)頁表相關(guān)問題

當進程訪問虛擬地址時,首先會查詢頁表以獲取對應的物理地址。如果頁表中找不到對應虛擬地址的頁表項(Page Table Entry,PTE),就會觸發(fā)頁異常 。這可能是因為該虛擬地址是無效的,就像你在一個公司的員工名單(頁表)中查找一個根本不存在的員工的工號(虛擬地址),自然是找不到的。

另一種情況是,虛擬地址是有效的,但對應的物理頁面尚未被載入主存,頁表項還沒有建立,就好比員工雖然存在,但還沒有分配工位(物理內(nèi)存位置),在名單上也沒有記錄其工位信息。比如在程序動態(tài)分配內(nèi)存時,malloc 函數(shù)只是在虛擬地址空間中預留了一段地址范圍,當進程首次訪問這段地址時,由于對應的物理內(nèi)存尚未分配和映射,就會導致頁表中沒有相應的 PTE,從而觸發(fā)頁異常 。

(2)訪問權(quán)限沖突

即使頁表中存在對應虛擬地址的 PTE,但如果該 PTE 的訪問權(quán)限設(shè)置拒絕當前進程的訪問操作,也會引發(fā)頁異常。例如,一個進程試圖對一個只讀的頁面進行寫入操作,而該頁面的 PTE 中設(shè)置了只讀權(quán)限,這就好比你拿著一張只能進入圖書館閱讀區(qū)的通行證,卻試圖進入書庫(禁止區(qū)域)取書,自然會被拒絕并觸發(fā)異常。這種情況通常用于保護系統(tǒng)關(guān)鍵數(shù)據(jù)和代碼,防止進程的非法訪問和修改,保障系統(tǒng)的穩(wěn)定性和安全性。

四、處理流程全解析

4.1捕獲與跳轉(zhuǎn)

當頁異常發(fā)生時,首先由 CPU 捕獲這個異常信號。就像在一個公司里,員工(進程)在執(zhí)行任務(wù)(訪問內(nèi)存)時遇到問題(頁異常),會立即向上級(CPU)報告 。CPU 捕獲到這個異常后,會跳轉(zhuǎn)到專門處理頁異常的函數(shù)page_fault_handler,這個函數(shù)就像是公司里專門處理問題的部門,負責解決內(nèi)存訪問異常的問題 。在page_fault_handler中,會進一步分析異常的原因和類型,為后續(xù)的處理做準備。

4.2處理邏輯分支

(1)無效地址處理

如果經(jīng)檢查發(fā)現(xiàn)訪問的地址是無效地址,屬于越界訪問,系統(tǒng)會返回segment fault錯誤 。這就好比員工試圖進入一個被禁止進入的辦公室(無效地址區(qū)域),會被保安(系統(tǒng))阻止并報告給上級。如果是用戶地址發(fā)生segment fault,系統(tǒng)會直接殺死該進程,以防止進程對系統(tǒng)造成進一步的破壞,就像公司會開除違反規(guī)定的員工 。而如果是內(nèi)核地址發(fā)生segment fault,情況則更為嚴重,可能會導致內(nèi)核崩潰,就像公司的核心管理層出現(xiàn)嚴重問題,可能會導致整個公司運營癱瘓 。

(2)有效地址處理

首次訪問:當頁是第一次被訪問時,會執(zhí)行demand_page_faults(請求調(diào)頁)操作 。這時候,系統(tǒng)會檢查頁表中是否存在該虛擬地址對應的頁表項(PTE),即通過pmd_none和pte_none等函數(shù)來判斷 。如果不存在,就需要分配新的頁幀,并對其進行初始化,從磁盤中讀取相應的數(shù)據(jù)到內(nèi)存中 。這就像是公司要為新入職的員工(新訪問的頁)分配一個工位(頁幀),并從倉庫(磁盤)中取出相關(guān)的辦公用品(數(shù)據(jù))放到工位上,以便員工能夠正常開展工作(進程能夠正常訪問內(nèi)存) 。

頁在 swap 分區(qū):如果頁被交換到了 swap 分區(qū),系統(tǒng)會檢查頁表項中的present標志位 。這個標志位就像是一個標簽,用來標識頁面是否在主存中 。如果present標志位為 0,表示該頁不在主存中,此時需要分配新的頁幀,并從磁盤的 swap 分區(qū)重新讀入內(nèi)存 。這就好比員工的辦公用品被暫時存放到了倉庫的臨時存儲區(qū)(swap 分區(qū)),當員工需要使用時,需要從臨時存儲區(qū)把辦公用品取回到工位(內(nèi)存)上 。

COW 情況:當vm_area_struct允許寫操作,但對應的頁表項(PTE)禁止寫操作時,就會觸發(fā)寫時復制(Copy-On-Write,COW)機制 。這是一種優(yōu)化策略,在多個進程共享同一個頁面時,只有當某個進程試圖對頁面進行寫操作時,才會真正復制出一個新的頁面供該進程使用,而不是在一開始就為每個進程都復制一份 。就好比多個員工共同使用一份文件(共享頁面),當其中一個員工想要修改文件內(nèi)容(寫操作)時,系統(tǒng)會為他復制一份文件副本(新頁面),讓他在副本上進行修改,而不影響其他員工使用的原始文件 。這樣可以節(jié)省內(nèi)存資源,提高系統(tǒng)的效率 。

五、實例與應用場景

5.1程序運行中的體現(xiàn)

以一個簡單的 C 程序為例,當程序執(zhí)行到malloc函數(shù)分配內(nèi)存時,實際上只是在虛擬地址空間中預留了一段地址范圍,并沒有立即分配物理內(nèi)存。只有當程序首次訪問這段地址時,才會觸發(fā)頁異常 。假設(shè)我們有如下 C 代碼:

#include <stdio.h>
#include <stdlib.h>

int main() {
    int *ptr = (int *)malloc(1024 * sizeof(int)); // 分配內(nèi)存,但未實際占用物理內(nèi)存
    if (ptr == NULL) {
        perror("malloc failed");
        return 1;
    }

    // 首次訪問分配的內(nèi)存,會觸發(fā)頁異常
    ptr[0] = 100; 

    printf("Value at ptr[0]: %d\n", ptr[0]);
    free(ptr);
    return 0;
}

在這段代碼中,malloc函數(shù)分配了一段虛擬內(nèi)存地址,當執(zhí)行ptr[0] = 100;時,由于這是首次訪問該地址,對應的物理內(nèi)存尚未分配和映射,系統(tǒng)會觸發(fā)頁異常。操作系統(tǒng)會捕獲這個異常,為該虛擬地址分配物理內(nèi)存頁幀,并建立虛擬地址與物理地址的映射關(guān)系,然后程序才能成功地將值 100 寫入ptr[0] 。

5.2系統(tǒng)性能影響

頁異常對系統(tǒng)性能有著顯著的影響,尤其是硬缺頁。由于硬缺頁需要從磁盤讀取數(shù)據(jù)到內(nèi)存,而磁盤 I/O 的速度遠遠慢于內(nèi)存訪問速度,頻繁的硬缺頁會導致系統(tǒng)性能大幅下降 。當一個進程頻繁地訪問大量數(shù)據(jù),而這些數(shù)據(jù)又不在物理內(nèi)存中時,就會不斷地觸發(fā)硬缺頁。比如一個數(shù)據(jù)庫管理系統(tǒng)在處理大量數(shù)據(jù)查詢時,如果內(nèi)存不足,無法緩存所有需要的數(shù)據(jù),就會頻繁地從磁盤讀取數(shù)據(jù),導致大量的硬缺頁發(fā)生。這不僅會增加磁盤 I/O 的負擔,還會使進程的執(zhí)行速度明顯變慢,進而影響整個系統(tǒng)的響應速度和吞吐量。

相比之下,軟缺頁的影響相對較小,因為它不需要從磁盤讀取數(shù)據(jù),只是建立映射關(guān)系,這個過程相對快速。但如果軟缺頁過于頻繁,也會消耗一定的系統(tǒng)資源,影響系統(tǒng)的整體性能 。例如,在一個多進程共享內(nèi)存的場景中,如果進程之間頻繁地訪問共享內(nèi)存,可能會導致大量的軟缺頁,因為每個進程在首次訪問共享內(nèi)存時都需要建立映射關(guān)系。雖然單個軟缺頁的處理時間較短,但大量的軟缺頁累積起來,也會對系統(tǒng)性能產(chǎn)生一定的影響。

責任編輯:武曉燕 來源: 深度Linux
相關(guān)推薦

2025-03-25 08:20:00

Linux虛擬內(nèi)存系統(tǒng)

2024-11-08 13:47:35

中文亂碼配置

2018-10-12 14:34:13

2011-05-24 11:26:11

2010-04-26 16:31:09

Oracle SQL

2010-05-12 14:18:58

Linux引導

2011-06-29 08:31:56

收錄

2010-05-21 13:05:41

MySQL錯誤

2010-08-31 09:06:25

Firefox margin-top

2024-09-26 00:00:10

死鎖阿里面試

2025-01-07 16:00:00

Kubernetes云原生Pod

2015-07-27 16:56:24

LinuxQQ

2010-01-22 15:42:01

VB.NET錯誤

2021-07-05 08:09:54

@AutowiredSpringMapper

2024-08-28 08:54:54

2018-08-21 09:03:00

SQLServer服務(wù)器

2021-06-30 07:08:14

安全解決方案XDR安全技術(shù)

2009-07-22 17:37:06

ASP.NET Ses

2010-05-26 13:14:22

MySQL錯誤解決方案

2010-03-26 18:41:51

Nginx 502錯誤
點贊
收藏

51CTO技術(shù)棧公眾號

欧洲亚洲视频| sm捆绑调教国产免费网站在线观看| 校园春色综合网| 国产一区二区三区在线观看视频| 孩娇小videos精品| 牛牛在线精品视频| 久久精品网站免费观看| 91免费高清视频| 日本一区二区三区四区五区| 日韩a一区二区| 精品欧美乱码久久久久久1区2区| avav在线看| 快射av在线播放一区| av资源网一区| 成人免费在线网址| 色婷婷av国产精品| 四虎8848精品成人免费网站| 欧美成人性战久久| 亚洲欧美激情网| 黑人玩欧美人三根一起进| 久久久美女毛片| 7777精品伊久久久大香线蕉语言| wwwwww国产| 午夜国产精品视频| 国产亚洲欧美日韩精品| 荫蒂被男人添免费视频| 国产亚洲欧美日韩精品一区二区三区| 亚洲国产美国国产综合一区二区| 午夜久久资源| 午夜视频www| 国产一区二区不卡在线| 国产精品久久久久久久一区探花| 日韩成人av毛片| 亚洲蜜桃视频| 久久精品99国产精品酒店日本| 亚洲第一页av| 久久动漫网址| 精品久久久久久亚洲综合网| 亚洲视频在线不卡| 国产激情久久| 在线视频你懂得一区二区三区| 可以看毛片的网址| 在线黄色网页| 中文字幕日韩av资源站| 欧洲一区二区日韩在线视频观看免费| 六月丁香综合网| 国产精品系列在线观看| 成人免费激情视频| 亚洲影视一区二区| 久久精品99久久久| 国产精品私拍pans大尺度在线| av片免费观看| 久久综合九色| 情事1991在线| 在线永久看片免费的视频| 国产日韩欧美一区| 91大神在线播放精品| 国产成人无码精品久在线观看| 欧美久色视频| 欧美激情在线狂野欧美精品| 中文字幕在线观看成人| 亚洲国产精品成人| 色综合久久88色综合天天看泰| 国产精品久久久精品四季影院| 亚洲国产精品91| 欧美尺度大的性做爰视频| 天天鲁一鲁摸一摸爽一爽| 99久久婷婷| 欧美成人免费网| 久久97人妻无码一区二区三区| 欧美不卡高清| 久久久久久免费精品| 国产 日韩 欧美 成人| 亚洲激情在线| 欧洲亚洲在线视频| 国产精品露脸视频| 国产一区二区福利视频| 古典武侠综合av第一页| 日韩黄色影片| 国产精品另类一区| 国产香蕉一区二区三区| 久久大胆人体| 色综合久久精品| 黄色手机在线视频| 视频一区国产| 亚洲欧美日韩一区二区在线 | xxxxx.日韩| 777色狠狠一区二区三区| 精品国产乱码久久久久久1区二区| 精品三级国产| 日韩精品一区二区视频| 国产白丝一区二区三区| 黄色成人91| 日韩**中文字幕毛片| 亚洲一二区视频| 懂色av一区二区夜夜嗨| 欧美精品久久久| 久久五月精品| 懂色av一区二区三区| 亚洲欧洲日本精品| 大奶一区二区三区| 中文字幕综合在线| 久草精品视频在线观看| 蜜臀av一区二区三区| 成人羞羞视频免费| 午夜伦理在线| 精品福利在线观看| gogogo高清免费观看在线视频| heyzo欧美激情| 一区二区三区动漫| 国产主播在线播放| 精品一区二区三区久久| 久久亚洲高清| 直接在线观看的三级网址| 色中色一区二区| www.黄色网| 天天色综合色| 国产ts一区二区| 亚洲精品久久久久久动漫器材一区 | 亚洲伦理在线观看| 国产精品久久久久天堂| 欧美激情 国产精品| 国产高清日韩| 色琪琪综合男人的天堂aⅴ视频| 日韩高清精品免费观看| 国产尤物一区二区| 日韩国产高清一区| 深夜av在线| 日韩久久久久久| 国产又粗又硬又长又爽| 日本aⅴ亚洲精品中文乱码| 精品中文字幕一区| 欧美人与牲禽动交com| 欧美麻豆精品久久久久久| 一区二区三区四区免费| 亚洲人成高清| 国产 高清 精品 在线 a| 精品黄色免费中文电影在线播放| 91福利小视频| 少妇真人直播免费视频| 影音先锋国产精品| 福利视频久久| 在线观看h网| 在线电影院国产精品| 性少妇xx生活| 日本免费在线视频不卡一不卡二| 欧美日韩精品免费观看视一区二区| 1区2区3区在线| 欧美电视剧在线看免费| 久久久久久久久精| 成人小视频免费在线观看| 青草网在线观看| 久久中文字幕一区二区| 欧美久久精品一级黑人c片| 国产一区二区波多野结衣| 中文字幕亚洲不卡| 黄色一级片免费的| 91精品国产调教在线观看| 成人福利免费观看| 超碰人人在线| 日韩精品在线一区二区| 日本熟妇色xxxxx日本免费看| 高潮精品一区videoshd| www.九色.com| 成人午夜网址| 97在线视频观看| 欧洲亚洲精品视频| 欧美性生活影院| 中文字幕电影av| 国产91精品欧美| 日日摸日日碰夜夜爽无码| 亚州av日韩av| 国产精品久久久久影院日本| 无遮挡的视频在线观看| 欧美不卡一区二区三区| 日韩成人在线免费视频| 久久久99精品久久| www.污污视频| 影院欧美亚洲| 日韩hmxxxx| 精品视频在线观看免费观看 | 亚洲成色999久久网站| 久久99精品波多结衣一区| 国产色产综合产在线视频| 九九精品久久久| 亚洲五月婷婷| 日韩国产在线一区| 日韩成人视屏| 欧洲一区二区视频| 国产激情在线视频| 亚洲精品久久久久久久久久久 | 久久久夜夜夜| 正义之心1992免费观看全集完整版| 99精品视频在线免费播放| 久久青草福利网站| 国产高清美女一级毛片久久| 日韩欧美一级二级| 好吊色在线视频| 亚洲视频免费观看| 插吧插吧综合网| 韩国三级电影一区二区| 人人干视频在线| 999精品在线| 九色综合婷婷综合| 国产精品中文| 国产成人亚洲综合91| 影音先锋中文在线视频| 亚洲人成电影在线播放| www.国产.com| 欧美伊人久久大香线蕉综合69| 欧美成人精品激情在线视频| 国产性色一区二区| 国产伦精品一区二区三区精品| 免费在线观看精品| 男人用嘴添女人下身免费视频| 国产大片一区| 日韩经典在线视频| 亚洲一区网址| 国产在线观看一区二区三区| 超碰国产一区| 久久全球大尺度高清视频| 浪潮av一区| 国产一区二区三区在线免费观看| 亚洲乱码在线观看| 制服丝袜一区二区三区| 国产男人搡女人免费视频| 亚洲va天堂va国产va久| 成年人av电影| 亚洲天堂免费在线观看视频| 精品成人无码一区二区三区| 91麻豆免费看| 中文字幕99页| 国产白丝精品91爽爽久久| 色婷婷激情视频| 蜜臀91精品一区二区三区| 久久精品一区二| 国产精品试看| 阿v天堂2017| 亚洲视频日本| 日本一本中文字幕| 黄色成人91| 少妇大叫太大太粗太爽了a片小说| 国产韩日影视精品| 日本免费在线视频观看| 国内成人自拍| 色综合影院在线观看| 国产欧美日韩视频在线| 欧美一区观看| 国产aⅴ精品一区二区三区久久| 久久99九九| 一区二区三区视频免费观看| 九九久久99| 亚洲国产欧美日韩在线观看第一区| 久久精品日韩| 九九亚洲精品| 婷婷久久青草热一区二区| 欧美日韩一二三四| 日本日本精品二区免费| 999久久久亚洲| 中文字幕免费高| 一区二区三区网站| 全黄性性激高免费视频| 中文久久精品| 国模杨依粉嫩蝴蝶150p| 免费高清视频精品| 男女视频在线观看网站| 国产成人综合在线观看| 中文字幕人妻一区| 91一区二区在线| www在线观看免费视频| 欧美激情一区二区三区不卡 | 好吊视频一二三区| 日韩国产高清视频在线| 国产原创av在线| 日韩在线免费视频| 欧美野外wwwxxx| 欧美亚洲视频在线看网址| 国产一区二区精品调教| 成人黄色av网| 成人爽a毛片| 日本一区不卡| 欧美一区网站| 无码精品国产一区二区三区免费| 男女激情视频一区| 日本少妇一级片| 久久麻豆一区二区| www.av免费| 欧美日韩国产综合视频在线观看中文| 成人免费一级片| 日韩一区二区在线播放| 色吊丝在线永久观看最新版本| 日韩亚洲欧美中文在线| 俺来也官网欧美久久精品| 国产精品国产三级国产aⅴ浪潮 | 精品一区在线播放| 精品日韩免费| 人人妻人人澡人人爽欧美一区双 | 91po在线观看91精品国产性色| 欧美精品资源| 粉嫩精品一区二区三区在线观看| 国产亚洲欧美日韩在线观看一区二区 | 人人爽久久涩噜噜噜网站| 久久精品97| 国产原创精品| 五月精品视频| 激情六月丁香婷婷| 国产成人无遮挡在线视频| 国产传媒国产传媒| 欧美日韩国产综合新一区| 国产麻豆一精品一男同| 亚洲欧美日韩爽爽影院| 暖暖在线中文免费日本| 91精品久久久久久| 亚洲欧美成人vr| 欧美一级中文字幕| 蜜臀久久99精品久久久久宅男| 波多野结衣先锋影音| 伊人一区二区三区| 一区二区三区精| 亚洲午夜久久久久久久| 波多野在线观看| 亚洲va久久久噜噜噜久久天堂| 亚洲最好看的视频| 日韩国产一级片| 国产成人8x视频一区二区| 国精产品一区一区| 欧美性黄网官网| 亚洲精品成人电影| 欧美精品在线看| 国产欧美日韩电影| 亚洲精品一区二区三区蜜桃久| 久久福利一区| 手机av免费看| 欧美性感美女h网站在线观看免费| 丰满岳乱妇国产精品一区| 久久视频在线播放| 激情欧美一区二区三区黑长吊| 日韩福利视频| 日韩高清不卡一区| 小早川怜子久久精品中文字幕| 欧美日韩国产中文精品字幕自在自线| 亚洲第一色网站| 欧美另类高清videos| 国产亚洲高清在线观看| 中文精品一区二区三区| 麻豆91在线看| 乱老熟女一区二区三区| 欧美日韩精品专区| 日本在线视频网| 成人综合国产精品| 中文字幕一区二区精品区| 污视频在线观看免费网站| 亚洲免费观看视频| 精品国产亚洲av麻豆| 欧美激情视频网址| 国产精品超碰| 凹凸国产熟女精品视频| 久久综合色天天久久综合图片| 成人av网站在线播放| 中文字幕免费精品一区高清| 成人18视频在线观看| 亚洲精品不卡| 国产精品系列在线播放| 国产成人精品av久久| 亚洲精品少妇网址| www.久久.com| 国产又粗又大又爽的视频| 国产宾馆实践打屁股91| 91香蕉在线视频| 亚洲欧美在线磁力| 日韩一区中文| 欧美人与动牲交xxxxbbbb| www.在线欧美| 日本一本在线观看| 久久精品中文字幕| 国产精品宾馆| 天堂av在线网站| 一区二区三区加勒比av| 天堂а√在线8种子蜜桃视频| 国产精品精品国产| 亚洲影视一区二区三区| 国模无码视频一区| 91传媒视频在线播放| 国产精品实拍| 精品一区在线播放| 麻豆国产91在线播放| 久久久久成人片免费观看蜜芽| 亚洲毛片在线看| 国产精品视频首页| 99精品在线免费视频| 国产精品少妇自拍| 韩国av在线免费观看| 日韩美女免费观看| 欧美+亚洲+精品+三区| 性少妇bbw张开| 日韩一区二区在线观看视频 | 精品一区二区视频在线观看 | 国产suv一区二区| 欧美在线视频一区二区| 天堂美国久久|