(2020.11.20 Fri)
CPU緩存躯泰、內(nèi)存和SD卡都有存儲功能,他們速度和容量各不相同安聘,且速度和容量是個矛盾痰洒。為兼顧性能和成本,計算機(jī)大多采取分級存儲的形式浴韭,使不同速度的存儲原件協(xié)同工作丘喻。
CPU緩存
CPU配上了兩級的高速緩存,讓CPU更快的提取到數(shù)據(jù)念颈。由于緩存造假高昂泉粉,容量并不大。
當(dāng)CPU需要讀寫某個內(nèi)存地址榴芳,它會先檢查該內(nèi)存地址的數(shù)據(jù)是否已經(jīng)存在于某條緩存記錄(cache entry)中嗡靡。如果緩存記錄中的內(nèi)存地址信息和CPU尋址信息相符,就說明數(shù)據(jù)已經(jīng)緩存了窟感,這種情況叫緩存命中(cache hit)讨彼。CPU會直接讀寫緩存中的目標(biāo)記錄,速度會比讀寫內(nèi)存快很多柿祈。如果CPU想要讀寫的數(shù)據(jù)不再緩存中哈误,稱為緩存缺失(cache miss)哩至,那么緩存會增加一條新的緩存記錄,把內(nèi)存地址的數(shù)據(jù)加載到該緩存記錄中蜜自。CPU隨后從緩存中讀寫數(shù)據(jù)菩貌。
緩存空間優(yōu)選,當(dāng)數(shù)據(jù)過多重荠,需要選擇替換緩存中的一個記錄菜谣。這條已經(jīng)存在的緩存記錄稱為犧牲者(victim)。新的緩存記錄會被放在犧牲者所在的位置晚缩。選擇犧牲者的方法有下面4種
- 最少使用(LFU, least frequently used)數(shù)據(jù)
- 最久沒有使用(LRU, least recently used)數(shù)據(jù)
- 最早被緩存(FIFO, first-in first-out)數(shù)據(jù)
- 隨機(jī)替換(random replacement)數(shù)據(jù)
以LRU為例尾膊,在該策略下,CPU為每個緩存記錄增加一個計數(shù)荞彼。當(dāng)CPU讀緩存時冈敛,LRU會把命中記錄的計數(shù)清零,而其他記錄的計數(shù)加1.如果一條記錄長期沒有被讀取鸣皂,那么它的計數(shù)就會越來越大抓谴。在選擇犧牲者時,CPU緩存會選擇計數(shù)最大的記錄作為犧牲者寞缝。該流程基于一層緩存癌压。
虛擬內(nèi)存如何利用緩存提高效率
除了數(shù)據(jù),CPU還會緩存來自內(nèi)存的指令及分頁記錄荆陆。很多技術(shù)的實(shí)現(xiàn)都離不開緩存帶來的效率滩届,以虛擬內(nèi)存為例,虛擬內(nèi)存技術(shù)可以實(shí)現(xiàn)很多功能比如構(gòu)建進(jìn)程空間和實(shí)現(xiàn)內(nèi)存共享被啼,但虛擬內(nèi)存并不免費(fèi)帜消。內(nèi)核必須記錄虛擬內(nèi)存頁和物理內(nèi)存頁的對應(yīng)關(guān)系,并花費(fèi)額外的CPU時間進(jìn)行地址轉(zhuǎn)換浓体。利用緩存技術(shù)把分頁記錄放在CPU內(nèi)部的高速元件上泡挺,可以有效解決尋址的效率問題。
頁交換
通過緩存技術(shù)命浴,彌補(bǔ)了CPU和內(nèi)存之間的速度差娄猫。而虛擬內(nèi)存技術(shù),可以把外部存儲器空間當(dāng)做內(nèi)存用生闲。虛擬內(nèi)存可以把一部分的外部存儲器空間換成內(nèi)存空間媳溺,使應(yīng)用程序可以虛擬的增加內(nèi)存大小。這個技術(shù)的關(guān)鍵在于頁交換(page swap)跪腹,也就是進(jìn)程空間和外部存儲空間以頁為單位交換數(shù)據(jù)褂删。虛擬內(nèi)存是管理數(shù)據(jù)和數(shù)據(jù)地址的方法,也可用于外部存儲空間的管理冲茸。操作系統(tǒng)把一部分外部存儲空間劃分成頁屯阀,稱作交換空間(swap space)缅帘。操作系統(tǒng)管理內(nèi)存的方式來管理交換空間。物理內(nèi)存加交換空間大大超越了實(shí)際存儲容量难衰。
為了保證讀寫效率钦无,程序只用在物理內(nèi)存中的虛擬內(nèi)存。當(dāng)程序訪問的數(shù)據(jù)恰好在交換空間時盖袭,內(nèi)核就會啟動頁交換失暂,把交換空間的頁轉(zhuǎn)移到物理內(nèi)存中,隨后內(nèi)核把分頁對應(yīng)到該物理內(nèi)存的位置鳄虱,通知程序繼續(xù)進(jìn)行數(shù)據(jù)操作弟塞。這樣,程序訪問的虛擬內(nèi)存地址就指向了物理內(nèi)存中的數(shù)據(jù)位置拙已。而應(yīng)用內(nèi)存只是根據(jù)虛擬內(nèi)存地址進(jìn)行操作决记,不需要知道內(nèi)核的幕后操作。
具體講倍踪,內(nèi)核記錄著虛擬內(nèi)存的對應(yīng)關(guān)系系宫。當(dāng)程序訪問虛擬內(nèi)存頁時,內(nèi)核會根據(jù)對應(yīng)關(guān)系建车,知道物理頁存在內(nèi)存還是外部存儲器中扩借。如果該頁存在外部存儲器,內(nèi)核則會讓進(jìn)城短暫休息缤至,然后將外部存儲器這一頁的內(nèi)容放入物理內(nèi)存中潮罪。如果內(nèi)存空間已滿,那么虛擬內(nèi)存要選擇把內(nèi)存中的一頁移出交換空間凄杯,從而為要進(jìn)入內(nèi)存的頁準(zhǔn)備好空間错洁。在這個過程中,內(nèi)存和外部存儲器交換了一頁戒突。移出內(nèi)存的頁充當(dāng)了犧牲者。Linux系統(tǒng)使用了一種類似于LRU的策略描睦,選擇最久沒有使用的分頁作為犧牲者膊存。
交換空間
一些具體的實(shí)施方法。交換空間有交換分區(qū)和交換文件兩種形式忱叭。分區(qū)就是用一個獨(dú)立的存儲器分區(qū)作為交換空間隔崎,和一般的磁盤分區(qū)不同,它沒有文件系統(tǒng)韵丑,完全以頁的方式進(jìn)行管理爵卒。交換文件是文件系統(tǒng)中的一個特殊文件,它占據(jù)的空間以頁的方式進(jìn)行管理撵彻,作為交換空間钓株。
$sudo swapon -s #查看交換空間
返回: filename type size used priority
返回的每一行是系統(tǒng)正在使用的交換空間。type字段表明該交換空間是一個分區(qū)而不是文件,通過filename可以知道交換分區(qū)是磁盤xxx胎撤。size字段表明磁盤大小平酿,單位KB。used字段表示有多少交換空間被使用受葛。priority字段表示linux系統(tǒng)的交換空間使用優(yōu)先級题涨。如果在Linux系統(tǒng)中掛載兩個或更多具有相同優(yōu)先級的交換空間,那么Linux會替換使用总滩。如果兩個交換空間正好位于兩種設(shè)備上纲堵,那么交替使用的方式可以提升交換性能。
$sudo mkswap /dev/hdb1 #mkswap把一個分區(qū)變成交換分區(qū)
$sudo swapon /dev/hdb1 # swapon激活交換分區(qū)
$sudo swapon -s #確認(rèn)/dev/hdb1已經(jīng)加入交換空間
$sudo dd if=/dev/zero of=/var/swapfile bs=1024 count=104875 #創(chuàng)建一個1GB的文件
$ #/var/swapfile是交換文件闰渔,選項(xiàng)count說明了文件大小婉支,104875KB
$mkswap /var/swapfile #用mkswap調(diào)用交換文件
$swapon /var/swapfile #激活交換文件,讓交換文件稱為可以使用的交換空間
外存的緩存和緩沖
內(nèi)存和外存速度差距極大澜建,讀寫文件時向挖,要想辦法彌補(bǔ)這個差距。CPU緩存技術(shù)就可以彌補(bǔ)該差距炕舵。
如果內(nèi)存中的部分空間可以用來緩存常用的文件系統(tǒng)數(shù)據(jù)何之,就可以大大減少外存的訪問量。這種技術(shù)就是頁緩存(page cache)咽筋,頁緩存和CPU緩存非常類似溶推。在讀取外存中的文件時,文件的數(shù)據(jù)會先存在內(nèi)存中未使用的頁上奸攻。此后蒜危,如果需要讀取相同的數(shù)據(jù),那么CPU可以直接從內(nèi)存中提取睹耐。當(dāng)內(nèi)存中可用于頁緩存的空間填滿時辐赞,計算機(jī)使用類似于LRU的策略選擇犧牲者,用新的文件數(shù)據(jù)來替換掉緩存頁硝训。free命令可以產(chǎn)卡內(nèi)存中頁緩存空間的大小
$free
返回結(jié)果中的cached那一列說明了頁緩存空間的大小响委。除了頁緩存,內(nèi)存還會在其他場景下使用緩存思想窖梁。比如赘风,內(nèi)存中會緩存文件系統(tǒng)的inode。讀取文件的inode纵刘,是獲取文件數(shù)據(jù)的第一步邀窃。對于頻繁讀寫的文件,如果能在內(nèi)存中緩存inode假哎,文件的讀寫效率也會大大提高瞬捕。
另一種思想:緩沖讀寫鞍历。例子:進(jìn)程往一個文件中寫入15個字符,進(jìn)程可以每次從內(nèi)存中拿一個字符寫入外存山析。由于外存寫入速度慢堰燎,那么在外存完成這個字符寫入的過程中,進(jìn)程都是閑置的笋轨。當(dāng)然秆剪,進(jìn)程可以進(jìn)入阻塞狀態(tài),把CPU讓給其他的進(jìn)程爵政。然而仅讽,進(jìn)程狀態(tài)切換需要付出代價。此外钾挟,外存寫入字符前需要進(jìn)行一些準(zhǔn)備動作洁灵,比如找到寫入快位置。分開寫入15個字符掺出,外存要重復(fù)15次準(zhǔn)備動作徽千。
緩沖的目的是在內(nèi)存中收集多個待寫入的字符,再一次性寫入外存汤锨。一方面減少了進(jìn)程切換的次數(shù)双抽,另一方面,外存可以共用一套準(zhǔn)備動作闲礼,從而減少開銷牍汹。內(nèi)存為進(jìn)程打開的文件保留緩沖區(qū)(buffer),用于收集待寫入文件的文本柬泽。緩沖區(qū)采用FIFO的策略慎菲。在刷新(flush)緩沖區(qū)時,緩沖區(qū)中存儲的文本會按照先后次序一次性寫入外存锨并。操作系統(tǒng)的內(nèi)核提供了緩沖區(qū)露该。因此,很多時候用write()系統(tǒng)寫一個字符到文件琳疏,字符并沒有真正存入文件有决。
刷新緩沖區(qū)的條件如下
- 緩沖區(qū)填滿了數(shù)據(jù)
- 文件關(guān)閉
- 進(jìn)程終結(jié)
- 文本中出現(xiàn)換行符
- 該文件出現(xiàn)數(shù)據(jù)讀取
內(nèi)核中內(nèi)置了緩沖讀寫功能。不過鑒于緩沖讀寫是一種簡單而有效的策略空盼,應(yīng)用程序也可以自己在進(jìn)程空間中安排緩沖區(qū),來把多次操作合并成一次操作新荤。事實(shí)上C標(biāo)準(zhǔn)庫中的標(biāo)準(zhǔn)IO函數(shù)揽趾,就負(fù)責(zé)在讀寫過程中管理進(jìn)程空間的緩沖區(qū)。IPC和網(wǎng)絡(luò)通信也經(jīng)常用到相似的緩沖策略苛骨,以提高通信效率篱瞎。
Reference
1 Vamei苟呐,周梓昕著,樹莓派開始玩轉(zhuǎn)Linux俐筋,中國工信出版集團(tuán)牵素,電子工業(yè)出版社