chinese直男口爆体育生外卖, 99久久er热在这里只有精品99, 又色又爽又黄18禁美女裸身无遮挡, gogogo高清免费观看日本电视,私密按摩师高清版在线,人妻视频毛茸茸,91论坛 兴趣闲谈,欧美 亚洲 精品 8区,国产精品久久久久精品免费

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫(xiě)文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

缺頁(yè)異常是匿名映射缺頁(yè)異常分析

Linux閱碼場(chǎng) ? 來(lái)源:韓傳華 ? 作者:韓傳華 ? 2020-09-09 10:55 ? 次閱讀
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

前面講到過(guò)寫(xiě)時(shí)復(fù)制缺頁(yè)異常(COW),一般用于父子進(jìn)程之間共享頁(yè),而我們會(huì)常見(jiàn)一種缺頁(yè)異常是匿名映射缺頁(yè)異常,今天我們就來(lái)討論下這種缺頁(yè)異常,讓大家徹底理解它。注:本文使用linux-5.0內(nèi)核源代碼。文章分為以下幾節(jié)內(nèi)容:

1.匿名映射缺頁(yè)異常的觸發(fā)情況2.0頁(yè)是什么?為什么使用0頁(yè)?

3.源代碼分析

3.1 觸發(fā)條件

3.2 第一次讀匿名頁(yè)

3.3 第一次寫(xiě)匿名頁(yè)

3.4 讀之后寫(xiě)匿名頁(yè)

4.應(yīng)用層實(shí)驗(yàn)

5.總結(jié)

在講解匿名映射缺頁(yè)異常之前我們先要了解以下什么是匿名頁(yè)?與匿名頁(yè)相對(duì)應(yīng)的是文件頁(yè),文件頁(yè)我們應(yīng)該很好理解,就是映射文件的頁(yè),如:通過(guò)mmap映射文件到虛擬內(nèi)存然后讀文件數(shù)據(jù),進(jìn)程的代碼數(shù)據(jù)段等,這些頁(yè)有后備緩存也就是塊設(shè)備上的文件,而匿名頁(yè)就是沒(méi)有關(guān)聯(lián)到文件的頁(yè),如:進(jìn)程的堆、棧等。還有一點(diǎn)需要注意:下面討論的都是私有的匿名頁(yè)的情況,共享匿名頁(yè)在內(nèi)核演變?yōu)槲募成淙表?yè)異常(偽文件系統(tǒng)),后面有機(jī)會(huì)我們會(huì)講解,感興趣的小伙伴可以看一看mmap的代碼實(shí)現(xiàn)對(duì)共享匿名頁(yè)的處理。

一,匿名映射缺頁(yè)異常的觸發(fā)情況

前面我們講解了什么是匿名頁(yè),那么思考一下什么情況下會(huì)觸發(fā)匿名映射缺頁(yè)異常呢?這種異常對(duì)于我們來(lái)說(shuō)非常常見(jiàn):

1.當(dāng)我們應(yīng)用程序使用malloc來(lái)申請(qǐng)一塊內(nèi)存(堆分配),在沒(méi)有使用這塊內(nèi)存之前,僅僅是分配了虛擬內(nèi)存,并沒(méi)有分配物理內(nèi)存,第一次去訪問(wèn)的時(shí)候才會(huì)通過(guò)觸發(fā)缺頁(yè)異常來(lái)分配物理頁(yè)建立和虛擬頁(yè)的映射關(guān)系。

2.當(dāng)我們應(yīng)用程序使用mmap來(lái)創(chuàng)建匿名的內(nèi)存映射的時(shí)候,頁(yè)同樣只是分配了虛擬內(nèi)存,并沒(méi)有分配物理內(nèi)存,第一次去訪問(wèn)的時(shí)候才會(huì)通過(guò)觸發(fā)缺頁(yè)異常來(lái)分配物理頁(yè)建立和虛擬頁(yè)的映射關(guān)系。

3.當(dāng)函數(shù)的局部變量比較大,或者是函數(shù)調(diào)用的層次比較深,導(dǎo)致了當(dāng)前的棧不夠用了,這個(gè)時(shí)候需要擴(kuò)大棧。當(dāng)然了上面的這幾種場(chǎng)景對(duì)應(yīng)應(yīng)用程序來(lái)說(shuō)是透明的,內(nèi)核為用戶(hù)程序做了大量的處理工作,下面幾節(jié)會(huì)看到如何處理。

二,0頁(yè)是什么?為什么使用0頁(yè)?

這里為什么會(huì)說(shuō)到0頁(yè)呢?什么是0頁(yè)呢?是地址為0的頁(yè)嗎?答案是:系統(tǒng)初始化過(guò)程中分配了一頁(yè)的內(nèi)存,這段內(nèi)存全部被填充0。下面我們來(lái)看下0頁(yè)如何分配的:在arch/arm64/mm/mmu.c中:

61/* 62 * Empty_zero_page is a special page that is used for zero-initialized data 63 * and COW. 64 */ 65 unsigned long empty_zero_page[PAGE_SIZE / sizeof(unsigned long)] __page_aligned_bss; 66 EXPORT_SYMBOL(empty_zero_page);

可以看到定義了一個(gè)全局變量,大小為一頁(yè),頁(yè)對(duì)齊到bss段,所有這段數(shù)據(jù)內(nèi)核初始化的時(shí)候會(huì)被清零,所有稱(chēng)之為0頁(yè)。

那么為什么使用0頁(yè)呢?一個(gè)是它的數(shù)據(jù)都是被0填充,讀的時(shí)候數(shù)據(jù)都是0,二是節(jié)約內(nèi)存,匿名頁(yè)面第一次讀的時(shí)候數(shù)據(jù)都是0都會(huì)映射到這頁(yè)中從而節(jié)約內(nèi)存(共享0頁(yè)),那么如果有進(jìn)程要去寫(xiě)這個(gè)這個(gè)頁(yè)會(huì)怎樣呢?答案是發(fā)生COW重新分配頁(yè)來(lái)寫(xiě)。

三,源代碼分析

3.1 觸發(fā)條件

當(dāng)?shù)谝还?jié)中的觸發(fā)情況發(fā)生的時(shí)候,處理器就會(huì)發(fā)生缺頁(yè)異常,從處理器架構(gòu)相關(guān)部分過(guò)渡到處理器無(wú)關(guān)部分,最終到達(dá)handle_pte_fault函數(shù):

3742 static vm_fault_t handle_pte_fault(struct vm_fault *vmf) 3743 { 3744 pte_t entry; ... 3782 if (!vmf->pte) { 3783 if (vma_is_anonymous(vmf->vma)) 3784 return do_anonymous_page(vmf); 3785 else 3786 return do_fault(vmf); 3787 }

3782和3783行是匿名映射缺頁(yè)異常的觸發(fā)條件:

1.發(fā)生缺頁(yè)的地址所在頁(yè)表項(xiàng)不存在。

2.是匿名頁(yè)發(fā)生的,即是vma->vm_ops為空。

當(dāng)滿(mǎn)足這兩個(gè)條件的時(shí)候就會(huì)調(diào)用do_anonymous_page函數(shù)來(lái)處理匿名映射缺頁(yè)異常。

2871 /* 2872 * We enter with non-exclusive mmap_sem (to exclude vma changes, 2873 * but allow concurrent faults), and pte mapped but not yet locked. 2874 * We return with mmap_sem still held, but pte unmapped and unlocked. 2875 */ 2876 static vm_fault_t do_anonymous_page(struct vm_fault *vmf) 2877 { 2878 struct vm_area_struct *vma = vmf->vma; 2879 struct mem_cgroup *memcg; 2880 struct page *page; 2881 vm_fault_t ret = 0; 2882 pte_t entry; 2883 2884 /* File mapping without ->vm_ops ? */ 2885 if (vma->vm_flags & VM_SHARED) 2886 return VM_FAULT_SIGBUS; 2887 2888/* 2889 |* Use pte_alloc() instead of pte_alloc_map(). We can't run 2890 |* pte_offset_map() on pmds where a huge pmd might be created 2891 |* from a different thread. 2892 |* 2893 |* pte_alloc_map() is safe to use under down_write(mmap_sem) or when 2894 |* parallel threads are excluded by other means. 2895 |* 2896 |* Here we only have down_read(mmap_sem). 2897 |*/ 2898 if (pte_alloc(vma->vm_mm, vmf->pmd)) 2899 return VM_FAULT_OOM; 2904 ...

2885行判斷:發(fā)生缺頁(yè)的vma是否為私有映射,這個(gè)函數(shù)處理的是私有的匿名映射。

2898行如何頁(yè)表不存在則分配頁(yè)表(有可能缺頁(yè)地址的頁(yè)表項(xiàng)所在的直接頁(yè)表不存在)。

3.2 第一次讀匿名頁(yè)情況

... 2905 /* Use the zero-page for reads */ 2906 if (!(vmf->flags & FAULT_FLAG_WRITE) && 2907 !mm_forbids_zeropage(vma->vm_mm)) { 2908 entry = pte_mkspecial(pfn_pte(my_zero_pfn(vmf->address), 2909 vma->vm_page_prot)); 2910 vmf->pte = pte_offset_map_lock(vma->vm_mm, vmf->pmd, 2911 vmf->address, &vmf->ptl); 2912 if (!pte_none(*vmf->pte)) 2913 goto unlock; 2914 ret = check_stable_address_space(vma->vm_mm); 2915 if (ret) 2916 goto unlock; 2917 /* Deliver the page fault to userland, check inside PT lock */ 2918 if (userfaultfd_missing(vma)) { 2919 pte_unmap_unlock(vmf->pte, vmf->ptl); 2920 return handle_userfault(vmf, VM_UFFD_MISSING); 2921 } 2922 goto setpte; 2923 } ... 2968 setpte: 2969 set_pte_at(vma->vm_mm, vmf->address, vmf->pte, entry);

?2906到2923行是處理的是私有匿名頁(yè)讀的情況:這里就會(huì)用到我們上面將的0頁(yè)了。

2906和 2907行判斷是否是由于讀操作導(dǎo)致的缺頁(yè)而且沒(méi)有禁止0頁(yè)。

2908-2909行是核心部分:設(shè)置頁(yè)表項(xiàng)的值映射到0頁(yè)。

我們主要研究這個(gè)語(yǔ)句:pfn_pte用來(lái)將頁(yè)幀號(hào)和頁(yè)表屬性拼接為頁(yè)表項(xiàng)值:

arch/arm64/include/asm/pgtable.h:77 #define pfn_pte(pfn,prot) 78 __pte(__phys_to_pte_val((phys_addr_t)(pfn) << PAGE_SHIFT) | pgprot_val(prot))

是將pfn左移PAGE_SHIFT位(一般為12bit),或上pgprot_val(prot)

先看my_zero_pfn:

include/asm-generic/pgtable.h:875staticinlineunsignedlongmy_zero_pfn(unsignedlongaddr) 876 { 877 extern unsigned long zero_pfn; 878 return zero_pfn; 879 }

||/

mm/memory.c: 126 unsigned long zero_pfn __read_mostly; 127 EXPORT_SYMBOL(zero_pfn); 128 129 unsigned long highest_memmap_pfn __read_mostly; 130 131 /* 132 * CONFIG_MMU architectures set up ZERO_PAGE in their paging_init() 133 */ 134 static int __init init_zero_pfn(void) 135 { 136 zero_pfn = page_to_pfn(ZERO_PAGE(0)); 137 return 0; 138 } 139 core_initcall(init_zero_pfn);

||/

arch/arm64/include/asm/pgtable.h:54/* 55 * ZERO_PAGE is a global shared page that is always zero: used 56 * for zero-mapped memory areas etc.. 57 */ 58 extern unsigned long empty_zero_page[PAGE_SIZE / sizeof(unsigned long)]; 59 #define ZERO_PAGE(vaddr) phys_to_page(__pa_symbol(empty_zero_page))

最終我們看到使用的就是內(nèi)核初始化設(shè)置的empty_zero_page這個(gè)0頁(yè)得到頁(yè)幀號(hào)。再看看pfn_pte的第二個(gè)參數(shù)vma->vm_pageprot,這是vma的訪問(wèn)權(quán)限,在做內(nèi)存映射mmap的時(shí)候會(huì)被設(shè)置。

那么我們想知道的時(shí)候是什么時(shí)候0頁(yè)被設(shè)置為了只讀屬性的(也就是頁(yè)表項(xiàng)何時(shí)被設(shè)置為只讀)?

我們帶著這個(gè)問(wèn)題去在內(nèi)核代碼中尋找答案。其實(shí)代碼看到這里一般看不到頭緒,但是我們要知道何時(shí)vma的vm_page_prot成員被設(shè)置的,如何被設(shè)置的,有可能就能找到答案。

我們到mm/mmap.c中去尋找答案:我們以do_brk_flags函數(shù)為例,這是設(shè)置堆的函數(shù)我們關(guān)注到3040行設(shè)置了vm_page_prot:

3040vma->vm_page_prot=vm_get_page_prot(flags);

||/

110 pgprot_t vm_get_page_prot(unsigned long vm_flags) 111 { 112 pgprot_t ret = __pgprot(pgprot_val(protection_map[vm_flags & 113 (VM_READ|VM_WRITE|VM_EXEC|VM_SHARED)]) | 114 pgprot_val(arch_vm_get_page_prot(vm_flags))); 115 116 return arch_filter_pgprot(ret); 117 } 118 EXPORT_SYMBOL(vm_get_page_prot);

vm_get_page_prot函數(shù)會(huì)根據(jù)傳遞來(lái)的vmflags是否為VMREAD|VMWRITE|VMEXEC|VMSHARED來(lái)轉(zhuǎn)換為保護(hù)位組合,繼續(xù)往下看||/

78 /* description of effects of mapping type and prot in current implementation. 79 * this is due to the limited x86 page protection hardware. The expected 80 * behavior is in parens: 81 * 82 * map_type prot 83 * PROT_NONE PROT_READ PROT_WRITE PROT_EXEC 84 * MAP_SHARED r: (no) no r: (yes) yes r: (no) yes r: (no) yes 85 * w: (no) no w: (no) no w: (yes) yes w: (no) no 86 * x: (no) no x: (no) yes x: (no) yes x: (yes) yes 87 * 88 * MAP_PRIVATE r: (no) no r: (yes) yes r: (no) yes r: (no) yes 89 * w: (no) no w: (no) no w: (copy) copy w: (no) no 90 * x: (no) no x: (no) yes x: (no) yes x: (yes) yes 91 * 92 * On arm64, PROT_EXEC has the following behaviour for both MAP_SHARED and 93 * MAP_PRIVATE: 94 * r: (no) no 95 * w: (no) no 96 * x: (yes) yes 97 */ 98 pgprot_t protection_map[16] __ro_after_init = { 99 __P000, __P001, __P010, __P011, __P100, __P101, __P110, __P111, 100 __S000, __S001, __S010, __S011, __S100, __S101, __S110, __S111 101 };

protection_map數(shù)組定義了從P000到S111一共16種組合,P表示私有(Private),S表示共享(Share),后面三個(gè)數(shù)字依次為可讀、可寫(xiě)、可執(zhí)行,如:_S010表示共享、不可讀、可寫(xiě)、不可執(zhí)行。

||/

arch/arm64/include/asm/pgtable-prot.h: 93 #define PAGE_NONE __pgprot(((_PAGE_DEFAULT) & ~PTE_VALID) | PTE_PROT_NONE | PTE_RDONLY | PTE_NG | PTE_PXN | PTE_UXN) 94 #define PAGE_SHARED __pgprot(_PAGE_DEFAULT | PTE_USER | PTE_NG | PTE_PXN | PTE_UXN | PTE_WRITE) 95 #define PAGE_SHARED_EXEC __pgprot(_PAGE_DEFAULT | PTE_USER | PTE_NG | PTE_PXN | PTE_WRITE) 96 #define PAGE_READONLY __pgprot(_PAGE_DEFAULT | PTE_USER | PTE_RDONLY | PTE_NG | PTE_PXN | PTE_UXN) 97 #define PAGE_READONLY_EXEC __pgprot(_PAGE_DEFAULT | PTE_USER | PTE_RDONLY | PTE_NG | PTE_PXN) 98 #define PAGE_EXECONLY __pgprot(_PAGE_DEFAULT | PTE_RDONLY | PTE_NG | PTE_PXN) 99 100 #define __P000 PAGE_NONE 101 #define __P001 PAGE_READONLY 102 #define __P010 PAGE_READONLY 103 #define __P011 PAGE_READONLY 104 #define __P100 PAGE_EXECONLY 105 #define __P101 PAGE_READONLY_EXEC 106 #define __P110 PAGE_READONLY_EXEC 107 #define __P111 PAGE_READONLY_EXEC 108 109 #define __S000 PAGE_NONE 110 #define __S001 PAGE_READONLY 111 #define __S010 PAGE_SHARED 112 #define __S011 PAGE_SHARED 113 #define __S100 PAGE_EXECONLY 114 #define __S101 PAGE_READONLY_EXEC 115 #define __S110 PAGE_SHARED_EXEC 116 #define __S111 PAGE_SHARED_EXEC

可以發(fā)現(xiàn)對(duì)于私有的映射只有只讀(PTE_RDONLY)沒(méi)有可寫(xiě)屬性(PTE_WRITE)105-107行,雖然之前設(shè)置的時(shí)候是設(shè)置了可寫(xiě)(VM_WRITE)!而對(duì)應(yīng)共享映射則會(huì)有可寫(xiě)屬性。

而這個(gè)被設(shè)置的保護(hù)位組合最終會(huì)在缺頁(yè)異常中被設(shè)置到頁(yè)表中:上面說(shuō)到的do_anonymous_page函數(shù):

2908 entry = pte_mkspecial(pfn_pte(my_zero_pfn(vmf->address),2909vma->vm_page_prot));

對(duì)于私有匿名映射的頁(yè),假設(shè)設(shè)置的vmflags為VMREAD|VMWRITE則對(duì)應(yīng)的保護(hù)位組合為:P110即為PAGE_READONLY_EXEC=pgprot(_PAGE_DEFAULT | PTE_USER | PTE_RDONLY | PT_ENG | PTE_PXN)不會(huì)設(shè)置為可寫(xiě)。

所以就將其頁(yè)表設(shè)置為了只讀?。。?/p>

2922行跳轉(zhuǎn)到setpte去將設(shè)置好的頁(yè)表項(xiàng)值填寫(xiě)到頁(yè)表項(xiàng)中。

當(dāng)匿名頁(yè)讀之后再次去寫(xiě)時(shí)候會(huì)由于頁(yè)表屬性為只讀導(dǎo)致COW缺頁(yè)異常,詳將COW相關(guān)文章,再此不在贅述。下面用圖說(shuō)話:

3.3 第一次寫(xiě)匿名頁(yè)的情況

接著do_anonymous_page函數(shù)繼續(xù)往下分析:

2876 static vm_fault_t do_anonymous_page(struct vm_fault *vmf) 2877 { ... 2924 2925 /* Allocate our own private page. */ 2926 if (unlikely(anon_vma_prepare(vma))) 2927 goto oom; 2928 page = alloc_zeroed_user_highpage_movable(vma, vmf->address); 2929 if (!page) 2930 goto oom; 2931 2932 if (mem_cgroup_try_charge_delay(page, vma->vm_mm, GFP_KERNEL, &memcg, 2933 false)) 2934 goto oom_free_page; 2935 2936 /* 2937 |* The memory barrier inside __SetPageUptodate makes sure that 2938 |* preceeding stores to the page contents become visible before 2939 |* the set_pte_at() write. 2940 |*/ 2941 __SetPageUptodate(page); 2942 2943 entry = mk_pte(page, vma->vm_page_prot); 2944 if (vma->vm_flags & VM_WRITE) 2945 entry = pte_mkwrite(pte_mkdirty(entry));2946 2947 vmf->pte = pte_offset_map_lock(vma->vm_mm, vmf->pmd, vmf->address, 2948 &vmf->ptl); 2949 if (!pte_none(*vmf->pte)) 2950 goto release; 2951 2952 ret = check_stable_address_space(vma->vm_mm); 2953 if (ret) 2954 goto release; 2955 2956 /* Deliver the page fault to userland, check inside PT lock */ 2957 if (userfaultfd_missing(vma)) { 2958 pte_unmap_unlock(vmf->pte, vmf->ptl); 2959 mem_cgroup_cancel_charge(page, memcg, false); 2960 put_page(page); 2961 return handle_userfault(vmf, VM_UFFD_MISSING); 2962 } 2963 2964 inc_mm_counter_fast(vma->vm_mm, MM_ANONPAGES); 2965 page_add_new_anon_rmap(page, vma, vmf->address, false); 2966 mem_cgroup_commit_charge(page, memcg, false, false); 2967 lru_cache_add_active_or_unevictable(page, vma);2968setpte:2969set_pte_at(vma->vm_mm,vmf->address,vmf->pte,entry); 2970 2971 /* No need to invalidate - it was non-present before */ 2972 update_mmu_cache(vma, vmf->address, vmf->pte); 2973 unlock: 2974 pte_unmap_unlock(vmf->pte, vmf->ptl); 2975 return ret; 2976 release: 2977 mem_cgroup_cancel_charge(page, memcg, false); 2978 put_page(page); 2979 goto unlock; 2980 oom_free_page: 2981 put_page(page); 2982 oom: 2983 return VM_FAULT_OOM; 2984 }

當(dāng)判斷不是讀操作導(dǎo)致的缺頁(yè)的時(shí)候,則是寫(xiě)操作造成,處理寫(xiě)私有的匿名頁(yè)情況,請(qǐng)記住這依然是第一次訪問(wèn)這個(gè)匿名頁(yè)只不過(guò)是寫(xiě)訪問(wèn)而已。

2928行會(huì)分配一個(gè)高端可遷移的被0填充的物理頁(yè)。2941設(shè)置頁(yè)中數(shù)據(jù)有效2943使用頁(yè)幀號(hào)和vma的訪問(wèn)權(quán)限設(shè)置頁(yè)表項(xiàng)值(注意:這個(gè)時(shí)候頁(yè)表項(xiàng)屬性依然為只讀)。

2944-2945行如果vma可寫(xiě),則設(shè)置頁(yè)表項(xiàng)值為臟且*可寫(xiě)*(這個(gè)時(shí)候才設(shè)置為可寫(xiě))。

2964行匿名頁(yè)計(jì)數(shù)統(tǒng)計(jì)2965行添加到匿名頁(yè)的反向映射中2967行添加到lru鏈表2969將設(shè)置好的頁(yè)表項(xiàng)值填充到頁(yè)表項(xiàng)中。

下面用圖說(shuō)話:

3.4 讀之后寫(xiě)匿名頁(yè)

讀之后寫(xiě)匿名頁(yè),其實(shí)已經(jīng)很簡(jiǎn)單了,那就是發(fā)生COW寫(xiě)時(shí)復(fù)制缺頁(yè)。下面依然看圖說(shuō)話:

四,應(yīng)用層實(shí)驗(yàn)

實(shí)驗(yàn)1:主要體驗(yàn)下內(nèi)核的按需分配頁(yè)策略!實(shí)驗(yàn)代碼:mmap映射10 * 4096 * 4096/1M=160M內(nèi)存空間,映射和寫(xiě)頁(yè)前后獲得內(nèi)存使用情況:

1 #include 2 #include 3 #include 4 #include 5 6 7 #define MAP_LEN (10 * 4096 * 4096) 8 9 int main(int argc, char **argv) 10 { 11 char *p; 12 int i; 13 14 15 puts("before mmap ->please exec: free -m "); 16 sleep(10); 17 p = (char *)mmap(0, MAP_LEN, PROT_READ |PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); 18 19 puts("after mmap ->please exec: free -m "); 20 puts("before write.... "); 21 sleep(10); 22 23 for(i=0;i <4096 *10; i++) 24 p[4096 * i] = 0x55; 25 26 27 puts("after write ->please exec: free -m "); 28 29 pause(); 30 31 return 0;32}

執(zhí)行結(jié)果:

出現(xiàn)“before mmap ->please exec: free -m”打印后執(zhí)行:

$ free -m 總計(jì) 已用 空閑 共享 緩沖/緩存 可用內(nèi)存:15921 6561 462 796 8897 8214交換:16290 702 15588

出現(xiàn)“after mmap ->please exec: free -m”打印后執(zhí)行:

$ free -m 總計(jì) 已用 空閑 共享 緩沖/緩存 可用內(nèi)存:15921 6565 483 771 8872 8236交換:16290 702 15588

出現(xiàn)“after write ->please exec: free -m”后執(zhí)行:

$:~/study/user_test/page-fault$ free -m 總計(jì) 已用 空閑 共享 緩沖/緩存 可用內(nèi)存:15921 6727 322 770 8871 8076交換:16290 702 15588

我們只關(guān)注已用內(nèi)存,可以發(fā)現(xiàn)映射前后基本上已用內(nèi)存沒(méi)有變化(考慮到其他內(nèi)存申請(qǐng)情況存在,也會(huì)有內(nèi)存變化)是6561M和6565M,說(shuō)明mmap的時(shí)候并沒(méi)有分配物理內(nèi)存,寫(xiě)之后發(fā)現(xiàn)內(nèi)存使用為6727M, 6727-6565=162M與我們mmap的大小基本一致,說(shuō)明了匿名頁(yè)實(shí)際寫(xiě)的時(shí)候才會(huì)分配等量的物理內(nèi)存。

實(shí)驗(yàn)2:主要體驗(yàn)下匿名頁(yè)讀之后寫(xiě)內(nèi)存頁(yè)申請(qǐng)情況實(shí)驗(yàn)代碼:mmap映射10 * 4096 * 4096/1M=160M內(nèi)存空間,映射、讀然后寫(xiě)頁(yè)前后獲得內(nèi)存使用情況:

1 #include 2 #include 3 #include 4 #include 5 6 7 #define MAP_LEN (10 * 4096 * 4096) 8 9 int main(int argc, char **argv) 10 { 11 char *p; 12 int i; 13 14 15 puts("before mmap...pls show free:. "); 16 sleep(10);? 17 p = (char *)mmap(0, MAP_LEN, PROT_READ |PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); 18 19 puts("after mmap.... "); 20 21 puts("before read...pls show free:. "); 22 sleep(10); 23 24 puts("start read.... "); 25 26 27 for(i=0;i <4096 *10; i++) 28 printf("%d ", p[4096 * i]); 29 printf(" "); 30 31 puts("after read....pls show free: "); 32 33 sleep(10); 34 35 puts("start write.... "); 36 37 for(i=0;i <4096 *10; i++) 38 p[4096 * i] = 0x55; 39 40 41 puts("after write...pls show free:. "); 42 43 pause(); 44 45 return 0; 46 }

執(zhí)行結(jié)果:出現(xiàn)"before mmap ->please exec: free -m" 后執(zhí)行:

$ free -m 總計(jì) 已用 空閑 共享 緩沖/緩存 可用內(nèi)存:15921 6590 631 780 8700 8164交換:16290 702 15588

出現(xiàn)"before read ->please exec: free -m"后執(zhí)行:

$ free -m 總計(jì) 已用 空閑 共享 緩沖/緩存 可用內(nèi)存:15921 6586 644 770 8690 8178交換:16290 702 15588

出現(xiàn)"after read ->please exec: free -m"后執(zhí)行:

$ free -m 總計(jì) 已用 空閑 共享 緩沖/緩存 可用內(nèi)存:15921 6587 624 789 8709 8158交換:16290 702 15588

出現(xiàn)"after write ->please exec: free -m"后執(zhí)行:

$ free -m 總計(jì) 已用 空閑 共享 緩沖/緩存 可用內(nèi)存:15921 6749 462 789 8709 7996交換:16290 702 15588

可以發(fā)現(xiàn):讀之后和之前基本上內(nèi)存使用沒(méi)有變化(實(shí)際上映射到了0頁(yè),這是內(nèi)核初始化時(shí)候分配好的),知道寫(xiě)之后6749-6587=162M符合預(yù)期,而且打印可以發(fā)現(xiàn)數(shù)據(jù)全為0。

分析:實(shí)際上,mmap的時(shí)候只是申請(qǐng)了一塊vma,讀的時(shí)候發(fā)生一次缺頁(yè)異常,映射到0頁(yè),所有內(nèi)存沒(méi)有分配,當(dāng)再次寫(xiě)這個(gè)頁(yè)面的時(shí)候,發(fā)生了COW分配新頁(yè)(cow中分配新頁(yè)的時(shí)候會(huì)判斷原來(lái)的頁(yè)是否為0頁(yè),如果為0頁(yè)就直接分配頁(yè)然后用0填充)。

五,總結(jié)

匿名映射缺頁(yè)異常是我們遇到的一種很常用的一種異常,對(duì)于匿名映射,映射完成之后,只是獲得了一塊虛擬內(nèi)存,并沒(méi)有分配物理內(nèi)存,當(dāng)?shù)谝淮卧L問(wèn)的時(shí)候:如果是讀訪問(wèn),會(huì)將虛擬頁(yè)映射到0頁(yè),以減少不必要的內(nèi)存分配;如果是寫(xiě)訪問(wèn),則會(huì)分配新的物理頁(yè),并用0填充,然后映射到虛擬頁(yè)上去。而如果是先讀訪問(wèn)一頁(yè)然后寫(xiě)訪問(wèn)這一頁(yè),則會(huì)發(fā)生兩次缺頁(yè)異常:第一次是匿名頁(yè)缺頁(yè)異常的讀的處理,第二次是寫(xiě)時(shí)復(fù)制缺頁(yè)異常處理。

原文標(biāo)題:Linux內(nèi)核虛擬內(nèi)存管理之匿名映射缺頁(yè)異常分析

文章出處:【微信公眾號(hào):Linuxer】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。

聲明:本文內(nèi)容及配圖由入駐作者撰寫(xiě)或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問(wèn)題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • Linux
    +關(guān)注

    關(guān)注

    88

    文章

    11749

    瀏覽量

    218931
  • COW
    COW
    +關(guān)注

    關(guān)注

    0

    文章

    4

    瀏覽量

    8161
  • 虛擬內(nèi)存
    +關(guān)注

    關(guān)注

    0

    文章

    79

    瀏覽量

    8445

原文標(biāo)題:Linux內(nèi)核虛擬內(nèi)存管理之匿名映射缺頁(yè)異常分析

文章出處:【微信號(hào):LinuxDev,微信公眾號(hào):Linux閱碼場(chǎng)】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。

收藏 人收藏
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

    評(píng)論

    相關(guān)推薦
    熱點(diǎn)推薦

    Cortex-M3工作模式及異常

    表 因?yàn)榈刂?0 處應(yīng)該存儲(chǔ)引導(dǎo)代碼,所以它通常映射到 Flash或者是 ROM 器件,并且它們的值不得在運(yùn)行時(shí)改變。然而,為了支持動(dòng)態(tài)重分發(fā)中斷, CM3 允許向量表重定位——從其它地址處開(kāi)始定位各異常
    發(fā)表于 01-20 08:24

    線路保護(hù)光纖通道異常處理方法

    在電力系統(tǒng)中,線路保護(hù)光纖通道是保障電網(wǎng)安全穩(wěn)定運(yùn)行的核心環(huán)節(jié)。然而,受環(huán)境、設(shè)備老化或人為操作等因素影響,光纖通道異常時(shí)有發(fā)生,可能導(dǎo)致保護(hù)裝置誤動(dòng)或拒動(dòng),引發(fā)嚴(yán)重后果。本文將系統(tǒng)梳理線路保護(hù)光纖
    的頭像 發(fā)表于 11-17 10:01 ?1039次閱讀
    線路保護(hù)光纖通道<b class='flag-5'>異常</b>處理方法

    電能質(zhì)量在線監(jiān)測(cè)裝置能自動(dòng)修復(fù)采樣異常數(shù)據(jù)嗎?

    展開(kāi)分析: 一、數(shù)據(jù)異常類(lèi)型與自動(dòng)修復(fù)技術(shù)實(shí)現(xiàn) 1. 常見(jiàn)異常類(lèi)型及自動(dòng)處理機(jī)制 瞬時(shí)干擾數(shù)據(jù)由電磁脈沖、信號(hào)毛刺等偶發(fā)因素導(dǎo)致的異常(如電壓瞬時(shí)跳變至 1000V),裝置可通過(guò)滑動(dòng)窗
    的頭像 發(fā)表于 09-26 09:22 ?446次閱讀
    電能質(zhì)量在線監(jiān)測(cè)裝置能自動(dòng)修復(fù)采樣<b class='flag-5'>異常</b>數(shù)據(jù)嗎?

    如何利用AI算法進(jìn)行裝置數(shù)據(jù)的異常檢測(cè)?

    利用 AI 算法進(jìn)行裝置數(shù)據(jù)異常檢測(cè),需結(jié)合工業(yè)裝置的數(shù)據(jù)特性(如實(shí)時(shí)性、多源性、強(qiáng)時(shí)序性、噪聲干擾)和業(yè)務(wù)需求(如故障預(yù)警、安全合規(guī)、工藝優(yōu)化),通過(guò) “數(shù)據(jù)預(yù)處理 - 算法選型 - 模型部署
    的頭像 發(fā)表于 09-05 15:27 ?1780次閱讀
    如何利用AI算法進(jìn)行裝置數(shù)據(jù)的<b class='flag-5'>異常</b>檢測(cè)?

    IGBT 樣品異常檢測(cè)案例解析

    通過(guò)利用Thermal EMMI(熱紅外顯微鏡)去檢測(cè)IGBT 樣品異常
    的頭像 發(fā)表于 08-15 09:17 ?1846次閱讀
    IGBT 樣品<b class='flag-5'>異常</b>檢測(cè)案例解析

    aicube項(xiàng)目頁(yè)初始化異常是怎么回事?

    一打開(kāi)軟件都出現(xiàn)“項(xiàng)目頁(yè)初始化異常”,新建項(xiàng)目顯示“最近項(xiàng)目加載異常 ” 期待結(jié)果和實(shí)際結(jié)果 軟硬件版本信息 嘉楠ai算法硬件平臺(tái)v1.4
    發(fā)表于 08-14 08:16

    判斷伺服行星減速機(jī)出現(xiàn)噪音的異常

    伺服行星減速機(jī)出現(xiàn)噪音通常被視為一種異常現(xiàn)象,這種噪音可能會(huì)影響設(shè)備的正常運(yùn)行,甚至對(duì)工作環(huán)境和操作人員的健康造成不良影響。以下是對(duì)伺服行星減速機(jī)出現(xiàn)噪音異常的判斷及可能原因的分析: 一、判斷標(biāo)準(zhǔn)
    的頭像 發(fā)表于 07-31 18:16 ?972次閱讀
    判斷伺服行星減速機(jī)出現(xiàn)噪音的<b class='flag-5'>異常</b>

    harmony-utils之CrashUtil,異常相關(guān)工具類(lèi)

    harmony-utils之CrashUtil,異常相關(guān)工具類(lèi)
    的頭像 發(fā)表于 07-04 16:33 ?506次閱讀

    【案例2.36】芯片啟動(dòng)異常的故障分析

    【案例2.36】芯片啟動(dòng)異常的故障分析在某產(chǎn)品的調(diào)試中發(fā)現(xiàn),板上核心處理芯片在每次啟動(dòng)后的表現(xiàn)不同,偶爾會(huì)出現(xiàn)無(wú)法啟動(dòng)的故障。經(jīng)過(guò)幾百次反復(fù)上下電測(cè)試發(fā)現(xiàn),在大多數(shù)情況下,芯片啟動(dòng)后能正常工作,但有
    的頭像 發(fā)表于 06-26 08:24 ?957次閱讀
    【案例2.36】芯片啟動(dòng)<b class='flag-5'>異常</b>的故障<b class='flag-5'>分析</b>

    機(jī)器學(xué)習(xí)異常檢測(cè)實(shí)戰(zhàn):用Isolation Forest快速構(gòu)建無(wú)標(biāo)簽異常檢測(cè)系統(tǒng)

    本文轉(zhuǎn)自:DeepHubIMBA無(wú)監(jiān)督異常檢測(cè)作為機(jī)器學(xué)習(xí)領(lǐng)域的重要分支,專(zhuān)門(mén)用于在缺乏標(biāo)記數(shù)據(jù)的環(huán)境中識(shí)別異常事件。本文深入探討異常檢測(cè)技術(shù)的理論基礎(chǔ)與實(shí)踐應(yīng)用,通過(guò)IsolationForest
    的頭像 發(fā)表于 06-24 11:40 ?1390次閱讀
    機(jī)器學(xué)習(xí)<b class='flag-5'>異常</b>檢測(cè)實(shí)戰(zhàn):用Isolation Forest快速構(gòu)建無(wú)標(biāo)簽<b class='flag-5'>異常</b>檢測(cè)系統(tǒng)

    Keithley 2400數(shù)字源表校準(zhǔn)數(shù)據(jù)異常時(shí)如何驗(yàn)證設(shè)備精度

    ,影響實(shí)驗(yàn)結(jié)論或產(chǎn)品質(zhì)量。因此,及時(shí)驗(yàn)證設(shè)備精度并排查異常原因,是確保測(cè)試可靠性的關(guān)鍵。本文將從設(shè)備原理、常見(jiàn)故障、驗(yàn)證方法等方面,系統(tǒng)介紹如何應(yīng)對(duì)校準(zhǔn)數(shù)據(jù)異常問(wèn)題。 ? 一、校準(zhǔn)數(shù)據(jù)異常的可能原因 在驗(yàn)證設(shè)備精度前,需先
    的頭像 發(fā)表于 06-10 12:03 ?679次閱讀
    Keithley 2400數(shù)字源表校準(zhǔn)數(shù)據(jù)<b class='flag-5'>異常</b>時(shí)如何驗(yàn)證設(shè)備精度

    PLC指示燈異常閃爍原因及維修

    PLC(可編程邏輯控制器)作為工業(yè)自動(dòng)化控制的核心設(shè)備,其運(yùn)行狀態(tài)的穩(wěn)定性直接影響生產(chǎn)線的效率與安全。指示燈作為PLC最直觀的狀態(tài)反饋窗口,其異常閃爍往往預(yù)示著潛在故障。本文將系統(tǒng)分析PLC指示燈
    的頭像 發(fā)表于 06-07 16:13 ?8403次閱讀
    PLC指示燈<b class='flag-5'>異常</b>閃爍原因及維修

    ups電源—常見(jiàn)UPS電源警報(bào)聲異常分析

    UPS電源(不間斷電源)警報(bào)聲是提示ups電源系統(tǒng)狀態(tài)的重要信號(hào)。當(dāng)UPS電源發(fā)出異常警報(bào)聲時(shí),往往意味著ups電源存在某種故障或異常情況。下面聊一下幾種常見(jiàn)的UPS電源警報(bào)聲異常情況及其可能原因
    的頭像 發(fā)表于 06-04 18:28 ?2258次閱讀
    ups電源—常見(jiàn)UPS電源警報(bào)聲<b class='flag-5'>異常</b><b class='flag-5'>分析</b>

    散熱設(shè)計(jì)與測(cè)試:PCBA異常發(fā)熱的解決之道

    在電子設(shè)備的生產(chǎn)和測(cè)試過(guò)程中,PCBA(印制電路板組裝)異常發(fā)熱是一個(gè)常見(jiàn)且棘手的問(wèn)題。過(guò)高的溫度不僅會(huì)影響設(shè)備的性能,還可能導(dǎo)致元器件損壞甚至設(shè)備報(bào)廢。因此,快速定位發(fā)熱原因并采取有效的解決措施
    的頭像 發(fā)表于 04-10 18:04 ?1581次閱讀

    異常零流量小區(qū)檢測(cè)功能介紹

    隨著5G部署規(guī)模不斷擴(kuò)大,網(wǎng)管KPI的分析需求突增也日益顯著,存在用戶(hù)感知問(wèn)題無(wú)法從告警和KPI數(shù)值中直接體現(xiàn)的情況;或者某些小區(qū)存在故障而網(wǎng)絡(luò)維護(hù)工程師無(wú)法及時(shí)監(jiān)控識(shí)別出來(lái)。異常零流量小區(qū),就是指
    的頭像 發(fā)表于 03-22 09:54 ?1062次閱讀
    <b class='flag-5'>異常</b>零流量小區(qū)檢測(cè)功能介紹