|
Linux系統(tǒng)內(nèi)存管理知識補充 Linux系統(tǒng)是虛擬內(nèi)存系統(tǒng),虛擬內(nèi)存并不是真正的物理內(nèi)存,而是虛擬的連續(xù)內(nèi)存地址空間。虛擬內(nèi)存又分為內(nèi)核空間和用戶空間,內(nèi)核空間是內(nèi)核程序運行的地方,用戶空間是用戶進程代碼運行的地方,只有內(nèi)核才能直接訪問物理內(nèi)存并為用戶空間映射物理內(nèi)存(MMU)。內(nèi)核會為每個進程分配獨立的連續(xù)的虛擬內(nèi)存空間,并且在需要的時候映射物理內(nèi)存,為了完成內(nèi)存映射,內(nèi)核為每個進程都維護了一張頁表,記錄虛擬地址與物理地址的映射關(guān)系,這個頁表就是存在于MMU中;用戶進程訪問內(nèi)存的時候,通過頁表把虛擬內(nèi)存地址轉(zhuǎn)換為物理內(nèi)存地址進而訪問數(shù)據(jù);其實對于用戶進程而言,虛擬內(nèi)存就是內(nèi)存一般的存在(當(dāng)作內(nèi)存看待就好)。這樣的設(shè)計可以把用戶程序和系統(tǒng)程序分開,互不影響;內(nèi)核可以對所有的用戶程序進行管理,比如限制內(nèi)存濫用等。 虛擬內(nèi)存的最小單位是頁,通常是4KB大小,所以虛擬內(nèi)存會有很多很多的頁組成,當(dāng)然也有大頁,顧名思義就是大的虛擬內(nèi)存空間,比如12KB,2MB。虛擬內(nèi)存和物理內(nèi)存的映射都是等空間的,映射的物理內(nèi)存是多大的,那么占用的虛擬內(nèi)存差不多也是多大,都是4KB的整數(shù)倍。比如映射了一個1KB的內(nèi)存空間,那么也是占用一頁4KB虛擬內(nèi)存。 用戶進程在處于用戶態(tài)時,只能訪問用戶空間;只有進入內(nèi)核態(tài)后,才可以訪問內(nèi)核空間。雖然每個進程的地址空間都包含了內(nèi)核空間,但這些內(nèi)核空間映射的物理內(nèi)存都是相同的,所以當(dāng)進程切換到內(nèi)核態(tài)后可以快速的訪問內(nèi)核空間數(shù)據(jù)。 內(nèi)核其實就是一段特殊的代碼程序,運行于內(nèi)核空間,控制著計算機的CPU、IO、內(nèi)存等,提供了一系列的系統(tǒng)接口供外部調(diào)用,通常叫做系統(tǒng)調(diào)用。只有線程或者進程處于內(nèi)核態(tài)的時候才能進行系統(tǒng)調(diào)用,如果處于用戶態(tài)的話,是需要轉(zhuǎn)換為內(nèi)核態(tài)才能訪問。其實就是權(quán)限不同,內(nèi)核態(tài)(Ring0)擁有比用戶態(tài)(Ring3)更高的權(quán)限,擁有著訪問系統(tǒng)硬件資源的權(quán)限。 一般用戶線程或者進程是不需要切換到內(nèi)核態(tài)運行的,除非: 1. 系統(tǒng)調(diào)用,其實系統(tǒng)調(diào)用本身就是中斷,但是軟件中斷,跟硬中斷不同。 2. 異常:如果當(dāng)前進程運行在用戶態(tài),如果這個時候發(fā)生了異常事件,就會觸發(fā)切換。 例如:缺頁異常。 3. 外設(shè)中斷:當(dāng)外設(shè)完成用戶的請求時,會向CPU發(fā)送中斷信號。 比如讀取硬盤數(shù)據(jù),除了IO屬于系統(tǒng)操作需要切換為內(nèi)核態(tài)來獲取權(quán)限的原因外還要一原因是: 為了減少磁盤的IO操作,為了提高性能而考慮的,因為我們的程序訪問一般都帶有局部性,也就是所謂的局部性原理,即我們訪問了文件的某一段數(shù)據(jù),那么接下去很可能還會訪問接下去的一段數(shù)據(jù),由于磁盤IO操作的速度比直接訪問內(nèi)存慢了好幾個數(shù)量級,所以O(shè)S根據(jù)局部性原理會在一次 read()系統(tǒng)調(diào)用過程中預(yù)讀更多的文件數(shù)據(jù)緩存在內(nèi)核IO緩沖區(qū)中,當(dāng)繼續(xù)訪問的文件數(shù)據(jù)在緩沖區(qū)中時便直接拷貝數(shù)據(jù)到進程私有空間,避免了再次的低效率磁盤IO操作。 傳統(tǒng)IO發(fā)送文件 1. 用戶程序調(diào)用read,進入內(nèi)核態(tài),上下文切換由用戶空間切換為內(nèi)核空間,由DMA(Direct Memory Access)加載文件數(shù)據(jù)到內(nèi)核空間。 2. CPU把數(shù)據(jù)從內(nèi)核空間復(fù)制到用戶空間,轉(zhuǎn)換為用戶態(tài),上下文由內(nèi)核空間切換為用戶空間。 3. 用戶程序調(diào)用write,再次進入內(nèi)核態(tài),CPU把數(shù)據(jù)從用戶空間復(fù)制到socket關(guān)聯(lián)的內(nèi)核空間。 4. 最后通過DMA 將內(nèi)核模式下的socket緩沖區(qū)中的數(shù)據(jù)復(fù)制到網(wǎng)卡設(shè)備中傳送,進而返回用戶空間進入用戶態(tài)。 sendfile零拷貝(<Linux 2.4) 1. 用戶程序調(diào)用read,進入內(nèi)核態(tài),上下文切換由用戶空間切換為內(nèi)核空間,由DMA(Direct Memory Access)加載文件數(shù)據(jù)到內(nèi)核空間,第一步和傳統(tǒng)IO相同。 2. 在內(nèi)核態(tài)下,CPU把數(shù)據(jù)從內(nèi)核空間復(fù)制到socket關(guān)聯(lián)的內(nèi)核空間。 3. 最后通過DMA 將內(nèi)核模式下的socket緩沖區(qū)中的數(shù)據(jù)復(fù)制到網(wǎng)卡設(shè)備中傳送,進而返回用戶空間進入用戶態(tài),最后一步也是和傳統(tǒng)IO相同。 與傳統(tǒng)IO相比,缺少了把數(shù)據(jù)從內(nèi)核空間復(fù)制到用戶空間,再由用戶空間復(fù)制到內(nèi)核空間,比原來缺少了一次CPU復(fù)制(復(fù)制3次,CPU參與復(fù)制一次),少了兩次上下文切換(兩次)。 **從內(nèi)核空間角度來看,其實已經(jīng)是“ZERO COPY”了,因為沒有往用戶空間復(fù)制的操作。** sendfile零拷貝(>=Linux 2.4) 1. 用戶程序調(diào)用read,進入內(nèi)核態(tài),上下文切換由用戶空間切換為內(nèi)核空間,由DMA(Direct Memory Access)加載文件數(shù)據(jù)到內(nèi)核空間,第一步和傳統(tǒng)IO相同。 2. 在內(nèi)核態(tài)下,描述符(包含了數(shù)據(jù)的位置和長度等信息)追加到socket關(guān)聯(lián)的緩沖區(qū)中,并沒有進行數(shù)據(jù)的拷貝。 3. 最后DMA根據(jù)提供的位置和偏移量信息直接將內(nèi)核空間緩沖區(qū)中的數(shù)據(jù)拷貝到協(xié)議引擎上進而返回用戶空間進入用戶態(tài)。 **這次優(yōu)化點在于沒有CPU參與復(fù)制,兩次DMA數(shù)據(jù)復(fù)制,不過還是兩次上下文切換。** # 通過mmap實現(xiàn)的零拷貝(常用來處理大文件) 當(dāng)進行mmap系統(tǒng)調(diào)用的時候,將文件的內(nèi)容的全部或一部分直接映射到進程的地址空間(虛擬內(nèi)存),映射完成后,進程可以像訪問普通內(nèi)存一樣做其他的操作,mmap并不分配物理地址空間,它只是占有進程的虛擬地址空間。 當(dāng)進程訪問內(nèi)核中的緩沖區(qū)時候,并沒有實際拷貝數(shù)據(jù),這時MMU在地址映射表中是無法找到與ptr相對應(yīng)的物理地址的,也就是MMU失敗,就會觸發(fā)缺頁中斷。內(nèi)核將文件的這一頁數(shù)據(jù)讀入到內(nèi)核高速緩沖區(qū)中,并更新用戶進程的頁表,使頁表指向內(nèi)核緩沖中的這一頁,實現(xiàn)了用戶空間和內(nèi)核空間數(shù)據(jù)的直接交換,可以看待為內(nèi)核空間和用戶空間共享的一段物理內(nèi)存。 Java調(diào)用零拷貝 FileInputStream input = new FileInputStream('1.txt');上面這種方式其實調(diào)用的是Linux系統(tǒng)的sendfile系統(tǒng)指令,無論什么語言代碼實現(xiàn)的零拷貝其實調(diào)用的都是操作系統(tǒng)本身提供的系統(tǒng)指令,只是做了封裝而已。 上面這種方式其實調(diào)用的是Linux系統(tǒng)的mmap系統(tǒng)指令;在讀取大文件的時候用這種方法映射大文件的一部分到內(nèi)存空間,比較方便快捷。 //mmap寫數(shù)據(jù)通過上面的測試可以看出在頻繁的寫入文件操作上mmap占有很多大的優(yōu)勢,數(shù)量級的優(yōu)勢。但是把上例的循環(huán)次數(shù)改為50的話,mmap就不占優(yōu)勢了,因為在映射的時候需要新開辟內(nèi)存空間,這個耗時相對于極少量的寫操作而言顯得占比重就大了。 來源: https://www.toutiao.com/i6810663802636337677/ |
|
|