一種提高操作系統(tǒng)大頁使用率的方法
【專利摘要】本發(fā)明公開了一種提高操作系統(tǒng)大頁使用率的方法。本方法為:1)系統(tǒng)在每一進(jìn)程的虛擬地址空間數(shù)據(jù)結(jié)構(gòu)中增加一變量a,記錄為進(jìn)程已經(jīng)分配虛擬地址的堆頂位置;2)進(jìn)程啟動時,系統(tǒng)將a初始化為0;當(dāng)該進(jìn)程調(diào)用堆頂設(shè)置函數(shù)進(jìn)行內(nèi)存申請時,向系統(tǒng)傳入一堆頂參數(shù)b;3)系統(tǒng)根據(jù)該進(jìn)程上一次請求的堆頂位置和當(dāng)前請求的堆頂位置b,計(jì)算堆頂位置向上大頁對齊之后的值c;4)系統(tǒng)將a的當(dāng)前值賦值給該進(jìn)程的記錄已分配內(nèi)存最高堆地址變量,并將其與c進(jìn)行比較:如果小于c,則根據(jù)二者差值增大該進(jìn)程的堆??臻g;如果小于c,則進(jìn)行內(nèi)存釋放,如果相等則不進(jìn)行內(nèi)存調(diào)用。本發(fā)明充分提升了大頁的使用率,進(jìn)而提升程序的性能。
【專利說明】一種提高操作系統(tǒng)大頁使用率的方法
【技術(shù)領(lǐng)域】
[0001]本發(fā)明涉及一種提高操作系統(tǒng)大頁使用率的方法,屬于操作系統(tǒng)內(nèi)存管理【技術(shù)領(lǐng)域】。
技術(shù)背景
[0002]分頁機(jī)制是現(xiàn)代CPU所共有的特征。它建立了一個從程序的虛擬內(nèi)存空間到機(jī)器的物理內(nèi)存之間的映射。內(nèi)存以頁為單位進(jìn)行管理。包括Intel x86在內(nèi)的很多CPU體系結(jié)構(gòu)實(shí)現(xiàn)了一種大頁機(jī)制,支持4k,2M,4M等多種不同大小的物理頁粒度。
[0003]目前的操作系統(tǒng)(例如Linux)為了簡單起見,普遍使用4K大小的頁,這種做法使得每一個映射覆蓋的虛擬地址的范圍只有4K。如果需要訪問一段長度為2M的內(nèi)存,操作系統(tǒng)需要處理512次缺頁中斷,每次缺頁中斷分配4K內(nèi)存。
[0004]以Linux操作系統(tǒng)為例,Linux自2.6.38開始支持透明大頁。使得操作系統(tǒng)能建立大小為2M (使用32位操作系統(tǒng)時為4M)的虛擬地址到物理地址映射,稱之為大頁映射(簡稱大頁)。使用大頁能夠減少TLB失效和CPU尋址時發(fā)生的計(jì)算和Cache開銷。該機(jī)制包含了幾個功能,例如物理頁碎片的整理,用以保證有足夠的大頁對齊的物理內(nèi)存供使用。在發(fā)生缺頁中斷(page fault)時進(jìn)行判斷,如果條件允許則使用大頁建立映射。一套針對大頁的內(nèi)存操作工具,提供了寫時復(fù)制等基本內(nèi)存操作。
[0005]該大頁模塊主要針對程序中的私有匿名內(nèi)存進(jìn)行優(yōu)化(一個程序使用的內(nèi)存絕大部分是以私用匿名的方式使用的。而且大頁并不適合在其他環(huán)境下使用。共享內(nèi)存使用大頁會增加寫時復(fù)制的開銷,映射到文件的內(nèi)存使用大頁會增加緩存的負(fù)擔(dān))。大頁的優(yōu)化不是強(qiáng)制的,而是采用“如果滿足條件,那么使用大頁”的邏輯。用“大頁使用率”來衡量Linux大頁模塊的使用程度。它等于:一個進(jìn)程的私有匿名內(nèi)存中,以大頁形式分配的內(nèi)存數(shù),除以程序總的私有匿名內(nèi)存使用量。
[0006]操作系統(tǒng)對內(nèi)存的分配是以page fault驅(qū)動的。每個進(jìn)程有自己的地址空間(在Linux系統(tǒng)中對應(yīng)mm_struct結(jié)構(gòu)),一個地址空間維護(hù)進(jìn)程的虛擬地址以及虛擬地址到物理地址的映射。一個進(jìn)程剛建立或者申請內(nèi)存的時候,進(jìn)程會調(diào)用函數(shù)申請一些虛擬內(nèi)存。這時候操作系統(tǒng)并不會立刻分配物理內(nèi)存,而是建立一個virtual memory area(以下簡稱vma),表示說,這段虛擬地址已經(jīng)被使用了。每一個mm_struct包含若干個vma,而每一個vma必定屬于某一個mm_StruCt。等到進(jìn)程實(shí)際讀寫這段虛擬地址的時候,因?yàn)闆]有分配內(nèi)存,一定會發(fā)生page fault。操作系統(tǒng)根據(jù)發(fā)生page fault的地址通過mm_struct定位到對應(yīng)的vma,根據(jù)發(fā)生page fault的原因和vma的屬性決定如何處理page fault。例如如果訪問到的虛擬地址不在任何vma里面,或者訪問的區(qū)域不是可讀的,那么就是訪問了非法的地址,返回segment fault,并殺死進(jìn)程。如果寫操作訪問了一個vma標(biāo)明可寫,但是頁表上標(biāo)記不可寫的地址時,那么是寫了寫時復(fù)制的頁面,操作系統(tǒng)會將頁面拷貝一份并重新設(shè)為可寫頁面。如果訪問的位置在vma內(nèi),但是沒有建立虛擬地址到物理地址的映射,那說明還沒有分配內(nèi)存,此時根據(jù)vma的類型,分配物理內(nèi)存,建立映射。[0007]建立內(nèi)存映射時會根據(jù)vma的情況決定是否使用大頁,一般來說,如果訪問地址上下2M對齊構(gòu)成的一段2M虛擬空間被所在vma包含,而且這段2M虛擬地址空間里面沒有建立過映射(二級頁表為空),那么Linux內(nèi)核會為這段虛擬地址分配大頁。如果上層申請內(nèi)存的時候沒有考慮大頁對齊的需求,申請的vma經(jīng)常不會2M對齊,這樣就無法使用大頁。
[0008]由于大頁分頁機(jī)制的固有限制,要求所有的物理地址和虛擬地址必須是對齊的。如果64位操作系統(tǒng)使用2M的頁進(jìn)行映射,那么虛擬地址的首尾必須2M對齊,物理地址的首尾也需要2M對齊。對于32位操作系統(tǒng),則在物理地址和虛擬地址4M對齊的情況下才能使用大頁。物理頁的管理是操作系統(tǒng)自己維護(hù)的,在透明大頁的實(shí)現(xiàn)中已經(jīng)具有了碎片整理功能,可以保證有足夠大頁對齊的物理頁用于建立大頁映射。虛擬地址一般是用戶申請的,不會考慮到底層是否有透明大頁的支持,因此虛擬地址申請時往往不是大頁對齊的。例如現(xiàn)在Linux透明大頁就存在這個問題。應(yīng)用程序虛擬地址的申請?jiān)诤芏嗲闆r下不滿足大頁對齊的要求,這使得Linux內(nèi)核不會分配大頁,轉(zhuǎn)而使用小頁。這種做法使得很多情況下,Linux內(nèi)核不會給程序分配大頁,大頁使用率不高。
【發(fā)明內(nèi)容】
[0009]針對現(xiàn)有技術(shù)中存在的技術(shù)問題,本發(fā)明的目的在于提供一種提高操作系統(tǒng)大頁使用率的方法,可有效的提升大頁的使用率,進(jìn)而提升了程序的性能。
[0010]本發(fā)明的技術(shù)方案為:
[0011]一種提高操作系統(tǒng)大頁使用率的方法,其步驟為:
[0012]I)系統(tǒng)在每一進(jìn)程的虛擬地址空間數(shù)據(jù)結(jié)構(gòu)中增加一變量a,用于記錄為進(jìn)程已經(jīng)分配虛擬地址的堆頂位置;并且修改堆起始設(shè)置函數(shù),使其返回的堆起始地址大頁對齊;
[0013]2)進(jìn)程啟動時,系統(tǒng)將變量a初始化為O ;當(dāng)該進(jìn)程調(diào)用堆頂設(shè)置函數(shù)進(jìn)行內(nèi)存申請時,向系統(tǒng)傳入一堆頂參數(shù)b,b為請求設(shè)置的新的堆頂位置;
[0014]3)系統(tǒng)根據(jù)該進(jìn)程上一次請求的堆頂位置和當(dāng)前請求的堆頂位置b,計(jì)算滿足該進(jìn)程當(dāng)前內(nèi)存需求的堆頂位置向上大頁對齊之后的值c ;
[0015]4)系統(tǒng)將該進(jìn)程變量a的當(dāng)前值賦值給該進(jìn)程的記錄已分配內(nèi)存最高堆地址變量,并將其與c進(jìn)行比較:如果小于C,則系統(tǒng)根據(jù)二者差值增大該進(jìn)程的堆??臻g;如果小于C,則根據(jù)二者差值進(jìn)行內(nèi)存釋放,減小該進(jìn)程的堆棧空間,如果相等,則不進(jìn)行內(nèi)存調(diào)用。
[0016]進(jìn)一步的,如果該進(jìn)程上一次請求的堆頂位置大于當(dāng)前請求的堆頂位置b,則從上一次請求的堆頂位置和c之間選取一較小值,系統(tǒng)檢查b到該較小值之間的虛擬地址是否已被分配了物理內(nèi)存,如果已被分配,則將這段物理內(nèi)存清O。
[0017]進(jìn)一步的,如果變量a的值為0,即系統(tǒng)還未對該進(jìn)程的堆分配過內(nèi)存,則系統(tǒng)將該進(jìn)程上一次請求的堆頂位置取值為該進(jìn)程的堆的起始地址。
[0018]進(jìn)一步的,所述堆起始設(shè)置函數(shù)返回的堆起始位置為向上大頁對齊后再減去一設(shè)定值。
[0019]進(jìn)一步的,所述變量a為長整形地址變量。
[0020]本發(fā)明解決對齊的問題核心思想是:在操作系統(tǒng)收到內(nèi)存申請的系統(tǒng)調(diào)用時,修改處理內(nèi)存申請的邏輯,在滿足用戶申請的前提下,額外分配一部分內(nèi)存,從而建立對齊的vma。分配額外內(nèi)存的時候,需要考慮如何有效利用這些額外內(nèi)存,減少內(nèi)存浪費(fèi);對于不可避免的浪費(fèi),需要在系統(tǒng)性能和內(nèi)存開銷之間權(quán)衡,以確定最優(yōu)方案。發(fā)明需要修改操作系統(tǒng)內(nèi)核的函數(shù),使得即使上層的內(nèi)存申請不滿足對齊要求,內(nèi)核可以創(chuàng)造大頁對齊的vma,滿足上層申請,并實(shí)現(xiàn)大頁。在處理的過程中,需要讓所做的修改和已有機(jī)制相容,并考慮可能造成的額外開銷。
[0021]圖1是Linux操作系統(tǒng)下進(jìn)程使用內(nèi)存的示意圖。箭頭表示調(diào)用,文字表示調(diào)用時需要提供的參數(shù)。一個C語言程序,使用內(nèi)存主要有這幾個地方:代碼段和數(shù)據(jù)段,全局變量段,堆,棧。在進(jìn)程啟動時,代碼段,數(shù)據(jù)段(已經(jīng)初始化的全局變量),bss段(未初始化的全局變量存放的地方)和棧就已經(jīng)建立了。它們有負(fù)責(zé)各自建立的函數(shù),其中使用的一部分在圖中標(biāo)明。
[0022]如果需要在程序運(yùn)行中動態(tài)申請內(nèi)存,有兩種方法可以使用。
[0023]一種方法是調(diào)用SyS_brk函數(shù)。每一個進(jìn)程都有一個堆空間,用來快速申請新的內(nèi)存。堆在操作系統(tǒng)里面是一個vma,由一套專門的函數(shù)負(fù)責(zé)管理,vma的低地址稱之為堆底,高地址稱之為堆頂,這段vma的內(nèi)存使用方式是私有匿名的,用戶可以在這段區(qū)域內(nèi)任意訪問。用戶只有一種方法操作堆,就是設(shè)置堆頂(堆底的位置在進(jìn)程建立時初始化,并且在整個進(jìn)程運(yùn)行過程中不能修改)。如果需要申請K字節(jié)的內(nèi)存,就設(shè)置新堆頂為原來的堆頂+K。相反的,如果想釋放內(nèi)存,那么只能釋放堆頂部分的內(nèi)存,通過將新堆頂設(shè)置得比原來的堆頂小,操作系統(tǒng)就會自動釋放新堆頂上方的內(nèi)存。操作系統(tǒng)提供的設(shè)置堆頂?shù)暮瘮?shù)為 sys_brk。
[0024]一個程序使用的私有匿名內(nèi)存都是通過這兩個函數(shù)分配的。本專利修改由brk函數(shù)申請的內(nèi)存。目的是通過修改,令其產(chǎn)生大頁對齊的vma。使得發(fā)生缺頁中斷時,操作系統(tǒng)會在這段vma內(nèi)分配大頁,從而提升大頁使用率。這個問題的難點(diǎn)在于malloc等上層程序申請內(nèi)存時沒有考慮大頁對齊,它們的參數(shù)不一定是大頁對齊的。我們需要在底層進(jìn)行修改,一方面滿足上層內(nèi)存申請的需求,另一方面維護(hù)vma滿足大頁對齊的限制。
[0025]對于操作系統(tǒng)來說,sys_brk函數(shù)修改的是一個特定vma,我們只要保證這個vma始終大頁對齊就可以保證通過sys_brk函數(shù)申請的內(nèi)存都會使用大頁。通過sys_brk修改vma時,不會改變vma的低地址,只會將vma的高地址來回移動。我們針對這一特征設(shè)計(jì)優(yōu)化的算法。在堆初始化時將堆對應(yīng)vma的低地址設(shè)置成大頁對齊的,從而保證了一側(cè)對齊。在另一側(cè),用戶設(shè)置的堆頂指針不一定是大頁對齊的。采用的方法是將vma的高地址往上擴(kuò)充到大頁對齊,并記錄用戶實(shí)際使用的堆頂?shù)奈恢?。通過預(yù)先分配內(nèi)存的方法實(shí)現(xiàn)了高地址的大頁對齊。同時記錄了用戶實(shí)際使用的位置,用戶見到的,是自己實(shí)際使用的位置,而不知道可能已經(jīng)分配了更多內(nèi)存。以后用戶申請內(nèi)存時,會從上次堆頂?shù)奈恢瞄_始申請,如果有一部分內(nèi)存已經(jīng)實(shí)現(xiàn)分配,那么可以直接使用,不會造成浪費(fèi)。這一機(jī)制對上層是透明的,可以在不需要修改上層應(yīng)用的情況下實(shí)現(xiàn)。
[0026]總地來說,通過控制堆起始地址和每次堆延伸的長度,可以保證堆所對應(yīng)的vma完全使用大頁。
[0027]與現(xiàn)有技術(shù)相比,本發(fā)明的積極效果為:
[0028]該發(fā)明以較小的代價(jià)提升的計(jì)算機(jī)系統(tǒng)的性能。優(yōu)化的代價(jià)主要是擴(kuò)充大頁虛擬地址時,額外的內(nèi)存開銷。它能有效地提升程序的性能。原有的Linux模塊的限制使得大頁使用率較低,在一些情況下,甚至完全不會使用大頁。通過該優(yōu)化,充分提升了大頁的使用率,進(jìn)而提升程序的性能。該優(yōu)化是針對內(nèi)核內(nèi)存管理的優(yōu)化,因此該優(yōu)化影響的程序范圍很廣,幾乎所有的程序都能通過該優(yōu)化受益。下面將以實(shí)驗(yàn)說明發(fā)明的優(yōu)勢。
[0029]使用SPECCPU2006作為測試程序集,對Linux大頁模塊和優(yōu)化進(jìn)行了測試,結(jié)果如表1:
[0030]表1為測試結(jié)果對比表
【權(quán)利要求】
1.一種提高操作系統(tǒng)大頁使用率的方法,其步驟為: O系統(tǒng)在每一進(jìn)程的虛擬地址空間數(shù)據(jù)結(jié)構(gòu)中增加一變量a,用于記錄為進(jìn)程已經(jīng)分配虛擬地址的堆頂位置;并且修改堆起始設(shè)置函數(shù),使其返回的堆起始地址大頁對齊; 2)進(jìn)程啟動時,系統(tǒng)將變量a初始化為O;當(dāng)該進(jìn)程調(diào)用堆頂設(shè)置函數(shù)進(jìn)行內(nèi)存申請時,向系統(tǒng)傳入一堆頂參數(shù)b,b為請求設(shè)置的新的堆頂位置; 3)系統(tǒng)根據(jù)該進(jìn)程上一次請求的堆頂位置和當(dāng)前請求的堆頂位置b,計(jì)算滿足該進(jìn)程當(dāng)前內(nèi)存需求的堆頂位置向上大頁對齊之后的值c ; 4)系統(tǒng)將該進(jìn)程變量a的當(dāng)前值賦值給該進(jìn)程的記錄已分配內(nèi)存最高堆地址變量,并將其與c進(jìn)行比較:如果小于C,則系統(tǒng)根據(jù)二者差值增大該進(jìn)程的堆??臻g;如果小于C,則根據(jù)二者差值進(jìn)行內(nèi)存釋放,減小該進(jìn)程的堆??臻g,如果相等,則不進(jìn)行內(nèi)存調(diào)用。
2.如權(quán)利要求1所述的方法,其特征在于如果該進(jìn)程上一次請求的堆頂位置大于當(dāng)前請求的堆頂位置b,則從上一次請求的堆頂位置和c之間選取一較小值,系統(tǒng)檢查b到該較小值之間的虛擬地址是否已被分配了物理內(nèi)存,如果已被分配,則將這段物理內(nèi)存清O。
3.如權(quán)利要求1所述的方法,其特征在于如果變量a的值為O,即系統(tǒng)還未對該進(jìn)程的堆分配過內(nèi)存,則系統(tǒng)將該進(jìn)程上一次請求的堆頂位置取值為該進(jìn)程的堆的起始地址。
4.如權(quán)利要求1所述的方法,其特征在于所述堆起始設(shè)置函數(shù)返回的堆起始位置為向上大頁對齊后再減去一設(shè)定值。
5.如權(quán)利要求1或2或3或4所述的方法,其特征在于所述變量a為長整形地址變量。
【文檔編號】G06F9/50GK103984599SQ201410146873
【公開日】2014年8月13日 申請日期:2014年4月14日 優(yōu)先權(quán)日:2014年4月14日
【發(fā)明者】汪小林, 羅韜威, 羅英偉 申請人:北京大學(xué)