新聞中心
Linux操作系統(tǒng)作為一種開(kāi)源的操作系統(tǒng),已經(jīng)在業(yè)界得到了廣泛的應(yīng)用和認(rèn)可。作為操作系統(tǒng)的核心,內(nèi)核的有效性和優(yōu)化對(duì)整個(gè)操作系統(tǒng)的性能和效率至關(guān)重要,而內(nèi)核物理頁(yè)分配機(jī)制則是內(nèi)核實(shí)現(xiàn)高效的關(guān)鍵之一。

內(nèi)核物理頁(yè)分配是指內(nèi)核在管理物理內(nèi)存時(shí),對(duì)于進(jìn)程請(qǐng)求的空間進(jìn)行合理的分配。這個(gè)過(guò)程不僅關(guān)乎進(jìn)程運(yùn)行的效率,也與操作系統(tǒng)的安全性和穩(wěn)定性密切相關(guān)。
在Linux內(nèi)核中,物理頁(yè)分配是通過(guò)伙伴系統(tǒng)實(shí)現(xiàn)的。為了提高內(nèi)核物理頁(yè)分配的效率,Linux內(nèi)核引用了伙伴算法,這種算法能夠避免內(nèi)存碎片和浪費(fèi)的問(wèn)題。
伙伴系統(tǒng)中,內(nèi)存被分成一些等大小的塊,每個(gè)塊都有相應(yīng)的伙伴——一個(gè)相同大小的塊。當(dāng)塊被申請(qǐng)時(shí),內(nèi)核會(huì)優(yōu)先選擇一組大小相同的伙伴,然后再把它們拼接成一個(gè)更大的塊,然后再次迭代,直到找到一個(gè)塊大于等于需要的大小。
隨著處理器速度和內(nèi)存大小的持續(xù)增長(zhǎng),對(duì)Linux內(nèi)核物理頁(yè)分配機(jī)制的優(yōu)化需求越來(lái)越高。而內(nèi)存分配與釋放是頻繁發(fā)生的事件,它們直接影響到操作系統(tǒng)的性能和用戶體驗(yàn)。
有很多因素影響了Linux內(nèi)核物理頁(yè)分配的效率,其中最重要的因素是內(nèi)存分配的方式。內(nèi)存分配方式的不同,直接影響到操作系統(tǒng)的性能和效率,而采用的分配方式不同,會(huì)對(duì)操作系統(tǒng)的內(nèi)存管理、交換等部分造成不同的影響。
在低端服務(wù)器和桌面計(jì)算機(jī)上,直接內(nèi)存分配是最常用的分配方式。這種分配方式的優(yōu)勢(shì)在于速度很快,因?yàn)樗恍枰M(jìn)行復(fù)雜的地址轉(zhuǎn)換和頁(yè)表查找。但是它的缺點(diǎn)也很明顯,它沒(méi)有按照邏輯分類的方式進(jìn)行分配,可能會(huì)造成內(nèi)存碎片的問(wèn)題。
另一種是池式內(nèi)存分配。這種分配方式與直接內(nèi)存分配方式類似,但它會(huì)根據(jù)需求動(dòng)態(tài)地分配內(nèi)存。這種方式的優(yōu)點(diǎn)是可以盡量避免內(nèi)存碎片問(wèn)題,然而,池式內(nèi)存分配不能很好地處理大塊內(nèi)存的申請(qǐng)請(qǐng)求。
雖然Linux內(nèi)核伙伴系統(tǒng)已經(jīng)為系統(tǒng)的內(nèi)存管理帶來(lái)了不小的提升,但是隨著計(jì)算機(jī)發(fā)展的迅速,對(duì)于內(nèi)核物理頁(yè)分配的要求也越來(lái)越高。
除了伙伴算法和內(nèi)存分配類型之外,需要考慮的其他因素包括內(nèi)存交換、進(jìn)程的內(nèi)存使用情況和內(nèi)存管理策略。在內(nèi)核物理頁(yè)分配方面,需要考慮的關(guān)鍵要素包括使用的算法、內(nèi)存池的大小、分配和釋放的鎖等等。
Linux內(nèi)核物理頁(yè)分配是提高操作系統(tǒng)效率的一個(gè)非常重要的因素。盡管Linux內(nèi)核已經(jīng)引入了伙伴算法和池式內(nèi)存分配等多種方式來(lái)優(yōu)化物理頁(yè)分配機(jī)制,但是在選擇合適的分配方式時(shí),還需根據(jù)實(shí)際需求情況靈活選擇。優(yōu)化物理頁(yè)分配機(jī)制不僅是內(nèi)核開(kāi)發(fā)人員的責(zé)任,也需要操作系統(tǒng)的用戶和系統(tǒng)管理員參與協(xié)同。通過(guò)共同努力,才能讓Linux系統(tǒng)內(nèi)核物理頁(yè)分配機(jī)制變得更加有效和高效。
相關(guān)問(wèn)題拓展閱讀:
- malloc()之后,內(nèi)核發(fā)生了什么?
malloc()之后,內(nèi)核發(fā)生了什么?
考慮這樣一種常見(jiàn)的情況:用戶進(jìn)程調(diào)用malloc()動(dòng)態(tài)分配了一塊內(nèi)存空間,悔亮再對(duì)這塊內(nèi)存進(jìn)行訪問(wèn)。這些用戶空間發(fā)生的事會(huì)引發(fā)內(nèi)核空間的那些反映?本文將簡(jiǎn)單為您解答。1.brk系統(tǒng)調(diào)用服務(wù)例程malloc()是一個(gè)API,這個(gè)函數(shù)在庫(kù)中封裝了系統(tǒng)調(diào)用brk。因此如果調(diào)用malloc,那么首先會(huì)引發(fā)brk系統(tǒng)調(diào)用執(zhí)行的過(guò)程。brk()在內(nèi)核中對(duì)應(yīng)的系統(tǒng)調(diào)用服務(wù)例程為SYSCALL_DEFINE1(brk, unsigned long, brk),參數(shù)brk用來(lái)指定heap段新的結(jié)束地址,也就是重新指定mm_struct結(jié)構(gòu)中的brk字段。brk系統(tǒng)調(diào)用服務(wù)例程首先會(huì)確定heap段的起始地址min_brk,然后再檢查資源的限制問(wèn)題。接著,將新老heap地址分別按枯渣照頁(yè)大小對(duì)齊,對(duì)齊后的地址分別存儲(chǔ)與newbrk和okdbrk中。brk()系統(tǒng)調(diào)用本身既可以縮小堆大小,又可以擴(kuò)大堆大小??s小堆這個(gè)功能是通過(guò)調(diào)用do_munmap()完成的。如果要擴(kuò)大堆的大小,那么必須先通過(guò)find_vma_intersection()檢查擴(kuò)大以后的堆是否與已經(jīng)存在的某個(gè)虛擬內(nèi)存重合,如何重合則直接退出。否則,調(diào)用do_brk()進(jìn)行接下來(lái)擴(kuò)大堆的各種工作。 SYSCALL_DEFINE1(brk, unsigned long, brk) { unsigned long rlim, retval; unsigned long newbrk, oldbrk; struct mm_struct *mm = current->mm; unsigned long min_brk; down_write(&mm->mmap_sem); #ifdef CONFIG_COMPAT_BRK min_brk = mm->end_code; #else min_brk = mm->start_brk; #endif if (brk start_brk) + (mm->end_data – mm->start_data) > rlim) newbrk = PAGE_ALIGN(brk); oldbrk = PAGE_ALIGN(mm->brk); if (oldbrk == newbrk) goto set_brk; if (brk brk) { if (!do_munmap(mm, newbrk, oldbrk-newbrk)) goto set_brk; goto out; } if (find_vma_intersection(mm, oldbrk, newbrk+PAGE_SIZE)) goto out; if (do_brk(oldbrk, newbrk-oldbrk) != oldbrk) goto out; set_brk: mm->brk = brk; out: retval = mm->brk; up_write(&mm->mmap_sem); return retval; } brk系統(tǒng)調(diào)用服務(wù)例程最后將返回堆的新結(jié)束地址。2.擴(kuò)大堆用戶進(jìn)程調(diào)用malloc()會(huì)使得內(nèi)核調(diào)用brk系統(tǒng)調(diào)用服務(wù)例程,因?yàn)閙alloc總是動(dòng)態(tài)的分配內(nèi)存空間,因此該服務(wù)例程此時(shí)會(huì)進(jìn)入第二條執(zhí)行路徑中,即擴(kuò)大堆。do_brk()主要完成以下工作:1.通過(guò)get_unmapped_area()在當(dāng)前進(jìn)程的地址空間中查找一個(gè)符合len大小的線性區(qū)間,并且該線性區(qū)間的必須在addr地址之后。如果找到了這個(gè)空閑的線性區(qū)間,則返回該區(qū)間的起始地址,否則返回錯(cuò)誤代碼-ENOMEM;2.通過(guò)find_vma_prepare()在當(dāng)前進(jìn)程所有線性區(qū)組成的紅黑樹(shù)中依次遍歷每個(gè)vma,以確定上一步找到的新區(qū)間之前的線性區(qū)對(duì)象的位置。如果addr位于某個(gè)現(xiàn)存的vma中,則調(diào)用do_munmap()刪除這個(gè)線性區(qū)。如果刪除成功則繼續(xù)查找,否則返回錯(cuò)誤代碼。3.目前已經(jīng)找到了一個(gè)合碧敗寬適大小的空閑線性區(qū),接下來(lái)通過(guò)vma_merge()去試著將當(dāng)前的線性區(qū)與臨近的線性區(qū)進(jìn)行合并。如果合并成功,那么該函數(shù)將返回prev這個(gè)線性區(qū)的vm_area_struct結(jié)構(gòu)指針,同時(shí)結(jié)束do_brk()。否則,繼續(xù)分配新的線性區(qū)。4.接下來(lái)通過(guò)kmem_cache_zalloc()在特定的slab高速緩存vm_area_cachep中為這個(gè)線性區(qū)分配vm_area_struct結(jié)構(gòu)的描述符。5.初始化vma結(jié)構(gòu)中的各個(gè)字段。6.更新mm_struct結(jié)構(gòu)中的vm_total字段,它用來(lái)同級(jí)當(dāng)前進(jìn)程所擁有的vma數(shù)量。7.如果當(dāng)前vma設(shè)置了VM_LOCKED字段,那么通過(guò)mlock_vma_pages_range()立即為這個(gè)線性區(qū)分配物理頁(yè)框。否則,do_brk()結(jié)束。可以看到,do_brk()主要是為當(dāng)前進(jìn)程分配一個(gè)新的線性區(qū),在沒(méi)有設(shè)置VM_LOCKED標(biāo)志的情況下,它不會(huì)立刻為該線性區(qū)分配物理頁(yè)框,而是通過(guò)vma一直將分配物理內(nèi)存的工作進(jìn)行延遲,直至發(fā)生缺頁(yè)異常。3.缺頁(yè)異常的處理過(guò)程經(jīng)過(guò)上面的過(guò)程,malloc()返回了線性地址,如果此時(shí)用戶進(jìn)程訪問(wèn)這個(gè)線性地址,那么就會(huì)發(fā)生缺頁(yè)異常(Page Fault)。整個(gè)缺頁(yè)異常的處理過(guò)程非常復(fù)雜,我們這里只關(guān)注與malloc()有關(guān)的那一條執(zhí)行路徑。當(dāng)CPU產(chǎn)生一個(gè)異常時(shí),將會(huì)跳轉(zhuǎn)到異常處理的整個(gè)處理流程中。對(duì)于缺頁(yè)異常,CPU將跳轉(zhuǎn)到page_fault異常處理程序中: //linux-2.6.34/arch/x86/kernel/entry_32.S ENTRY(page_fault) RING0_EC_FRAME pushl $do_page_fault CFI_ADJUST_CFA_OFFSET 4 ALIGN error_code: ………… jmp ret_from_exception CFI_ENDPROC END(page_fault) 該異常處理程序會(huì)調(diào)用do_page_fault()函數(shù),該函數(shù)通過(guò)讀取CR2寄存器獲得引起缺頁(yè)的線性地址,通過(guò)各種條件判斷以便確定一個(gè)合適的方案來(lái)處理這個(gè)異常。3.1.do_page_fault()該函數(shù)通過(guò)各種條件來(lái)檢測(cè)當(dāng)前發(fā)生異常的情況,但至少do_page_fault()會(huì)區(qū)分出引發(fā)缺頁(yè)的兩種情況:由編程錯(cuò)誤引發(fā)異常,以及由進(jìn)程地址空間中還未分配物理內(nèi)存的線性地址引發(fā)。對(duì)于后一種情況,通常還分為用戶空間所引發(fā)的缺頁(yè)異常和內(nèi)核空間引發(fā)的缺頁(yè)異常。內(nèi)核引發(fā)的異常是由vmalloc()產(chǎn)生的,它只用于內(nèi)核空間內(nèi)存的分配。顯然,我們這里需要關(guān)注的是用戶空間所引發(fā)的異常情況。這部分工作從do_page_fault()中的good_area標(biāo)號(hào)處開(kāi)始執(zhí)行,主要通過(guò)handle_mm_fault()完成。 //linux-2.6.34/arch/x86/mm/fault.c dotraplinkage void __kprobes do_page_fault(struct pt_regs *regs, unsigned long error_code) { ………… good_area: write = error_code & PF_WRITE; if (unlikely(access_error(error_code, write, vma))) { bad_area_access_error(regs, error_code, address); return; } fault = handle_mm_fault(mm, vma, address, write ? FAULT_FLAG_WRITE : 0); ………… } 3.2.handle_mm_fault()該函數(shù)的主要功能是為引發(fā)缺頁(yè)的進(jìn)程分配一個(gè)物理頁(yè)框,它先確定與引發(fā)缺頁(yè)的線性地址對(duì)應(yīng)的各級(jí)頁(yè)目錄項(xiàng)是否存在,如何不存在則分進(jìn)行分配。具體如何分配這個(gè)頁(yè)框是通過(guò)調(diào)用handle_pte_fault()完成的。 int handle_mm_fault(struct mm_struct *mm, struct vm_area_struct *vma, unsigned long address, unsigned int flags) { pgd_t *pgd; pud_t *pud; pmd_t *pmd; pte_t *pte; ………… pgd = pgd_offset(mm, address); pud = pud_alloc(mm, pgd, address); if (!pud) return VM_FAULT_OOM; pmd = pmd_alloc(mm, pud, address); if (!pmd) return VM_FAULT_OOM; pte = pte_alloc_map(mm, pmd, address); if (!pte) return VM_FAULT_OOM; return handle_pte_fault(mm, vma, address, pte, pmd, flags); } 3.3.handle_pte_fault()該函數(shù)根據(jù)頁(yè)表項(xiàng)pte所描述的物理頁(yè)框是否在物理內(nèi)存中,分為兩大類:請(qǐng)求調(diào)頁(yè):被訪問(wèn)的頁(yè)框不再主存中,那么此時(shí)必須分配一個(gè)頁(yè)框。寫(xiě)時(shí)復(fù)制:被訪問(wèn)的頁(yè)存在,但是該頁(yè)是只讀的,內(nèi)核需要對(duì)該頁(yè)進(jìn)行寫(xiě)操作,此時(shí)內(nèi)核將這個(gè)已存在的只讀頁(yè)中的數(shù)據(jù)復(fù)制到一個(gè)新的頁(yè)框中。用戶進(jìn)程訪問(wèn)由malloc()分配的內(nèi)存空間屬于之一種情況。對(duì)于請(qǐng)求調(diào)頁(yè),handle_pte_fault()仍然將其細(xì)分為三種情況: static inline int handle_pte_fault(struct mm_struct *mm, struct vm_area_struct *vma, unsigned long address, pte_t *pte, pmd_t *pmd, unsigned int flags) { ………… if (!pte_present(entry)) { if (pte_none(entry)) { if (vma->vm_ops) { if (likely(vma->vm_ops->fault)) return do_linear_fault(mm, vma, address, pte, pmd, flags, entry); } return do_anonymous_page(mm, vma, address, pte, pmd, flags); } if (pte_file(entry)) return do_nonlinear_fault(mm, vma, address, pte, pmd, flags, entry); return do_swap_page(mm, vma, address, pte, pmd, flags, entry); } ………… } 1.如果頁(yè)表項(xiàng)確實(shí)為空(pte_none(entry)),那么必須分配頁(yè)框。如果當(dāng)前進(jìn)程實(shí)現(xiàn)了vma操作函數(shù)中的fault鉤子函數(shù),那么這種情況屬于基于文件的內(nèi)存映射,它調(diào)用do_linear_fault()進(jìn)行分配物理頁(yè)框。否則,內(nèi)核將調(diào)用針對(duì)匿名映射分配物理頁(yè)框的函數(shù)do_anonymous_page()。2.如果檢測(cè)出該頁(yè)表項(xiàng)為非線性映射(pte_file(entry)),則調(diào)用do_nonlinear_fault()分配物理頁(yè)。3.如果頁(yè)框事先被分配,但是此刻已經(jīng)由主存換出到了外存,則調(diào)用do_swap_page()完成頁(yè)框分配。由malloc分配的內(nèi)存將會(huì)調(diào)用do_anonymous_page()分配物理頁(yè)框。3.4.do_anonymous_page()此時(shí),缺頁(yè)異常處理程序終于要為當(dāng)前進(jìn)程分配物理頁(yè)框了。它通過(guò)alloc_zeroed_user_highpage_movable()來(lái)完成這個(gè)過(guò)程。我們層層撥開(kāi)這個(gè)函數(shù)的外衣,發(fā)現(xiàn)它最終調(diào)用了alloc_pages()。 static int do_anonymous_page(struct mm_struct *mm, struct vm_area_struct *vma, unsigned long address, pte_t *page_table, pmd_t *pmd, unsigned int flags) { ………… if (unlikely(anon_vma_prepare(vma))) goto oom; page = alloc_zeroed_user_highpage_movable(vma, address); if (!page) goto oom; ………… } 經(jīng)過(guò)這樣一個(gè)復(fù)雜的過(guò)程,用戶進(jìn)程所訪問(wèn)的線性地址終于對(duì)應(yīng)到了一塊物理內(nèi)存。參考:1.《深入理解LINUX內(nèi)核》2.《深入LINUX內(nèi)核架構(gòu)》
linux 內(nèi)核為進(jìn)程分配物理頁(yè)的介紹就聊到這里吧,感謝你花時(shí)間閱讀本站內(nèi)容,更多關(guān)于linux 內(nèi)核為進(jìn)程分配物理頁(yè),Linux內(nèi)核物理頁(yè)分配,提升進(jìn)程運(yùn)行效率,malloc()之后,內(nèi)核發(fā)生了什么?的信息別忘了在本站進(jìn)行查找喔。
香港服務(wù)器選創(chuàng)新互聯(lián),2H2G首月10元開(kāi)通。
創(chuàng)新互聯(lián)(www.cdcxhl.com)互聯(lián)網(wǎng)服務(wù)提供商,擁有超過(guò)10年的服務(wù)器租用、服務(wù)器托管、云服務(wù)器、虛擬主機(jī)、網(wǎng)站系統(tǒng)開(kāi)發(fā)經(jīng)驗(yàn)。專業(yè)提供云主機(jī)、虛擬主機(jī)、域名注冊(cè)、VPS主機(jī)、云服務(wù)器、香港云服務(wù)器、免備案服務(wù)器等。
分享文章:Linux內(nèi)核物理頁(yè)分配,提升進(jìn)程運(yùn)行效率(linux內(nèi)核為進(jìn)程分配物理頁(yè))
本文URL:http://www.fisionsoft.com.cn/article/cdsssgs.html


咨詢
建站咨詢
