歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux基礎 >> 關於Linux >> Linux的內存管理概述

Linux的內存管理概述

日期:2017/3/3 16:00:25   编辑:關於Linux

在Linux中經常發現空閒內存很少,似乎所有的內存都被系統占用了,表面感覺是內存不夠用了,其實不然。這是Linux內存管理的一個優秀特性,在這方面,區別於 Windows的內存管理。主要特點是,無論物理內存有多大,Linux 都將其充份利用,將一些程序調用過的硬盤數據讀入內存,利用內存讀寫的高速特性來提高Linux系統的數據訪問性能。而Windows 是只在需要內存時,才為應用程序分配內存,並不能充分利用大容量的內存空間。換句話說,每增加一些物理內存,Linux 都將能充分利用起來,發揮了硬件投資帶來的好處,而Windows只將其做為擺設,即使增加8GB甚至更大。

Linux 的這一特性,主要是利用空閒的物理內存,劃分出一部份空間,做為 cache 和 buffers ,以此提高數據訪問性能。

1、什麼是 cache

頁高速緩存(cache)是 Linux內核實現的一種主要磁盤緩存。它主要用來減少對磁盤的I/O操作。具體地講,是通過把磁盤中的數據緩存到物理內存中,把對磁盤的訪問變為對物理內存的訪問。

磁盤高速緩存的價值在於兩個方面:第一,訪問磁盤的速度要遠遠低於訪問內存的速度,因此,從內存訪問數據比從磁盤訪問速度更快。第二,數據一旦被訪問,就很有可能在短期內再次被訪問到。

頁高速緩存是由內存中的物理頁組成的,緩存中每一頁都對應著磁盤中的多個塊。每當內核開始執行一個頁I/O操作時(通常是對普通文件中頁大小的塊進行磁盤操作),首先會檢查需要的數據是否在高速緩存中,如果在,那麼內核就直接使用高速緩存中的數據,從而避免訪問磁盤。

舉個例子,當使用文本編輯器打開一個源程序文件時,該文件的數據就被調入內存。編輯該文件的過程中,越來越多的數據會相繼被調入內存頁。最後,當你編譯它的時候,內核可以直接使用頁高速緩存中的頁,而不需要重新從磁盤讀取該文件了。因為用戶往往會反復讀取或操作同一個文件,所以頁高速緩存能減少大量的磁盤操作。

2、cache 如何更新

由於頁高速緩存的緩存作用,寫操作實際上會被延遲。當頁高速緩存中的數據比後台存儲的數據更新時,那麼該數據就被稱做髒數據。在內存中累積起來的髒頁最終必須被寫回磁盤。在以下兩種情況發生時,髒頁被寫回磁盤:

◆當空閒內存低於一個特定的阈值時,內核必須將髒頁寫回磁盤,以便釋放內存。

◆當髒頁在內存中駐留時間超過一個特定的阈值時,內核必須將超時的髒頁寫回磁盤,以確保髒頁不會無限期地駐留在內存中。

在2.6內核中,由一群內核線程—pdflush後台回寫例程統一執行兩種工作。

首先,pdflush線程在系統中的空閒內存低於一個特定的阈值時,將髒頁刷新回磁盤。該後台回寫例程的目的在於在可用物理內存過低時,釋放髒頁以重新獲得內存。特定的內存阈值可以通過dirty_background_ratio sysctl系統調用設置。當空閒內存比阈值:dirty_background_ratio還低時,內核便會調用函數wakeup_bdflush()喚醒一個pdflush線程,隨後pdflush線程進一步調用函數background_writeout()開始將髒頁寫回磁盤。函數background_ writeout()需要一個長整型參數,該參數指定試圖寫回的頁面數目。函數background_writeout()會連續地寫出數據,直到滿足以下兩個條件:

◆已經有指定的最小數目的頁被寫出到磁盤。

◆空閒內存數已經回升,超過了阈值dirty_background_ratio。

上述條件確保了pdflush操作可以減輕系統中內存不足的壓力。回寫操作不會在達到這兩個條件前停止,除非pdflush寫回了所有的髒頁,沒有剩下的髒頁可再被寫回了。

為了滿足第二個目標,pdflush後台例程會被周期性喚醒(和空閒內存是否過低無關),將那些在內存中駐留時間過長的髒頁寫出,確保內存中不會有長期存在的髒頁。如果系統發生崩潰,由於內存處於混亂之中,所以那些在內存中還沒來得及寫回磁盤的髒頁就會丟失,所以周期性同步頁高速緩存和磁盤非常重要。在系統啟動時,內核初始化一個定時器,讓它周期地喚醒pdflush線程,隨後使其運行函數wb_kupdate()。

本章描述了Linux內存管理的特性,也即,虛擬內存和磁盤緩沖。敘述了系統管理員需要考慮到的內存管理的目的、工作原理以及其他一些事情。

1、什麼是虛擬內存

Linux支持虛擬內存(virtual memory),虛擬內存是指使用磁盤當作RAM的擴展,這樣可用的內存的大小就相應地增大了。內核會將暫時不用的內存塊的內容寫到硬盤上,這樣一來,這塊內存就可用於其它目的。當需要用到原始的內容時,它們被重新讀入內存。這些操作對用戶來說是完全透明的;Linux下運行的程序只是看到有大量的內存可供使用而並沒有注意到時不時它們的一部分是駐留在硬盤上的。當然,讀寫硬盤要比直接使用真實內存慢得多(要慢數千倍),所以程序就不會象一直在內存中運行的那樣快。用作虛擬內存的硬盤部分被稱為交換空間(swap space)。

Linux能夠使用文件系統中的一個常規文件或一個獨立的分區作為交換空間。交換分區要快一些,但是很容易改變交換文件的大小(也就無需重分區整個硬盤,並且可以從臨時分區中安裝任何東西)。當你知道你需要多大的交換空間時,你應該使用交換分區,但是如果你不能確定的話,你可以首先使用一個交換文件,然後使用一陣子系統,你就可以感覺到要有多大的交換空間,此時,當你能夠確信它的大小時就創建一個交換分區。

你應該知道,Linux允許同時使用幾個交換分區以及/或者交換文件。這意味著如果你只是偶爾地另外需要一個交換空間時,你可以在當時設置一個額外的交換文件,而不是一直分配這個交換空間。

操作系統術語注釋:計算機科學常常將交換[swapping](將整個進程寫到交換空間)與頁面調度[paging](在某個時刻,僅僅固定大小的幾千字節寫到交換空間內)加以區別。頁面調度通常更有效,這也是Linux的做法,但是傳統的Linux術語卻指的是交換。

2、創建交換空間

一個交換文件是一個普通的文件;對內核來說一點也不特殊。對內核有關系的是它不能有孔,並且它是用mkswap來准備的。而且,它必須駐留在一個本地硬盤上,它不能由於實現的原因而駐留在一個通過NFS加載的文件系統中。

本文URL:http://www.bianceng.cn/OS/Linux/201410/45613.htm

關於孔是重要的。交換文件保留了磁盤空間,以至於內核能夠快速地交換出頁面而無需做分配磁盤扇區給文件時所要做的一些事。內核僅僅是使用早已分配給交換文件的任何扇區而已。因為文件中的一個孔意味著沒有磁盤扇區分配(給該文件的孔的相應部分),對內核來說就不能使用這類有孔的文件。

創建無孔的交換文件的一個好方法是通過下列命令:

$ dd if=/dev/zero of=/extra-swap bs=1024 count=1024

上面/extra-swap是交換文件的名字,大小由count=後面的數值給出。大小最好是4的倍數,因為內核寫出的內存頁面(memory pages)大小是4千字節。如果大小不是4的倍數,最後幾千字節就用不上了。

一個交換分區也並沒有什麼特別的。你可以象創建其它分區一樣地創建它;唯一的區別在於它是作為一個原始的分區使用的,也即,它不包括任何的文件系統。將交換分區標記為類型82(Linux交換分區)是個好主意;這將使得分區的列表更清楚,盡管對內核來說並不是一定要這樣的。

在創建了一個交換文件或一個交換分區以後,你必須在它的開頭部分寫上一個簽名;這個簽名中包括了一些由內核使用的管理信息。這是用\cmd{mkswap}命令來做到的,用法如下:

$ mkswap /extra-swap 1024

Setting up swapspace, size = 1044480 bytes

請注意此時交換空間還沒有被使用:它已存在,但內核還沒有用它作為虛擬內存。你必須非常小心地使用mkswap,因為它不檢查這個文件或分區是否已被別人使用。你可以非常容易地使用mkswap來覆蓋重要的文件以及分區!幸運的是,僅僅在安裝系統時,你才需要使用mkswap。

Linux內存管理程序限制每個交換空間最大約為127MB(由於各種技術上的原因,實際的限制大小為(4096-10) * 8 * 4096 = 133890048$ 字節,或127.6875兆字節)。然而,你可以同時使用多至16個交換空間,總容量幾乎達2GB。

交換空間的使用

一個已初始化的交換空間是使用命令swapon投入正式使用的。該命令告訴內核這個交換空間可以被使用了。到交換空間的路徑是作為參數給出的,所以,開始在一個臨時交換文件上使用交換的命令如下:

$ swapon /extra-swap

通過把交換空間列入/etc/fstab文件中就能被自動地使用了。

/dev/hda8 none swap sw 0 0

/swapfile none swap sw 0 0

啟動描述文件會執行命令swapon –a,這個命令會啟動列於/etc/fstab中的所有交換空間。因此,swapon命令通常僅用於需要有外加的交換空間時。

你可以用free命令監視交換空間的使用情況。它將給出已使用了多少的交換空間。

total used free shared buffers

輸出的第一行(Mem:)顯示出物理內存的使用情況。總和(total)列中並沒有顯示出被內核使用的內存,它通常將近一兆字節。已用列(used column)顯示出已用內存的總和(第二行沒有把緩沖算進來)。空閒列(free column)顯示了所有未被使用的空閒內存。共享列(shared column)顯示出了被幾個進程共享的內存的大小;共享的內存越多,情況就越好。緩存列(buffer column)顯示出了當前磁盤緩存的大小。已緩沖列(cached column)顯示出了已使用的緩存的大小。

最後一行(Swap:)顯示出了與交換空間相應的信息。如果這一行的數值都是零,表示你的交換空間沒有被擊活。

也可通過用top命令來獲得同樣的信息,或者使用proc文件系統中的文件/proc/meminfo 。通常要取得指定交換空間的使用情況是困難的。

可以使用命令swapoff來移去一個交換空間。通常沒有必要這樣做,但臨時交換空間除外。一般,在交換空間中的頁面首先被換入內存;如果此時沒有足夠的物理內存來容納它們又將被交換出來(到其他的交換空間中)。如果沒有足夠的虛擬內存來容納所有這些頁面,Linux就會波動而不正常;但經過一段較長的時間Linux會恢復,但此時系統已不可用了。在移去一個交換空間之前,你應該檢查(例如,用free)是否有足夠的空閒內存。

任何由swapon –a而自動被使用的所有交換空間都能夠用swapoff –a命令移去;該命令參考/etc/fstab文件來確定移去什麼。任何手工設置使用的交換空間將始終可以被使用。

有時,盡管有許多的空閒內存,仍然會有許多的交換空間正被使用。這是有可能發生的,例如如果在某一時刻有進行交換的必要,但後來一個占用很多物理內存的大進程結束並釋放內存時。被交換出的數據並不會自動地交換進內存,除非有這個需要時。此時物理內存會在一段時間內保持空閒狀態。對此並沒有什麼可擔心的,但是知道了是怎麼一回事我們也就放心了。

許多操作系統使用了虛擬內存的方法。因為它們僅在運行時才需要交換空間,以即決不會在同一時間使用交換空間,因此,除了當前正在運行的操作系統的交換空間,其它的就是一種浪費。所以讓它們共享一個交換空間將會更有效率。這是可能的,但需要有一定的了解。在HOWTO技巧文檔中含有如何實現這種做法的一些建議。

有些人會對你說需要用物理內存的兩倍容量來分配交換空間,但這是不對的。下面是合適的做法:

。估計你的總內存需求。這是某一時刻你所需要的最大的內存容量,也就是在同一時刻你想運行的所有程序所需內存的總和。通過同時運行所有的程序你可以做到這一點。

例如,如果你要運行X,你將給它分配大約8MB內存,gcc需要幾兆字節(有些文件要求異呼尋常的大量的內存量,多至幾十兆字節,但通常約4兆字節應該夠了),等等。內核本身要用大約1兆字節、普通的shell以及其它一些工具可能需要幾百千字節(就說總和要1兆字節吧)。並不需要進行精確的計算,粗率的估計也就足夠了,但你必須考慮到最壞的情況。

注意,如果會有幾個人同時使用這個系統,他們都將消耗內存。然而,如果兩個人同時運行一個程序,內存消耗的總量並不是翻倍,因為代碼頁以及共享的庫只存在一份。

Free以及ps命令對估計所需的內存容量是很有幫助的。

對第一步中的估計放寬一些。這是因為對程序在內存中占用多少的估計通常是不准的,因為你很可能忘掉幾個你要運行的程序,以及,確信你還要有一些多余的空間用於以防萬一。這需幾兆字節就夠了。(多分配總比少分配交換空間要好,但並不需要過分這樣以至於使用整個硬盤,因為不用的交換空間是浪費的空間;參見後面的有關增加交換空間。)同樣,因為處理數值更好做,你可以將容量值加大到整數兆字節。

基於上面的計算,你就知道了你將需要總和為多少的內存。所以,為了分配交換空間,你僅需從所需總內存量中減去實際物理內存的容量,你就知道了你需要多少的交換空間。(在某些UNIX版本中,你還需要為物理內存的映像分配空間,所以第二步中算出的總量正是你所需要的交換空間的容量,而無需再做上述中的減法運算了。)

如果你計算出的交換空間容量遠遠大於你的物理內存(大於兩倍以上),你通常需要再買些內存來,否則的話,系統的性能將非常低。

有幾個交換空間是個好主意,即使計算指出你一個都不需要。Linux系統常常動不動就使用交換空間,以保持盡可能多的空閒物理內存。即使並沒有什麼事情需要內存,Linux也會交換出暫時不用的內存頁面。這可以避免等待交換所需的時間:當磁盤閒著,就可以提前做好交換。

可以將交換空間分散在幾個硬盤之上。針對相關磁盤的速度以及對磁盤的訪問模式,這樣做可以提高性能。你可能想實驗幾個方案,但是你要認識到這些實驗常常是非常困難的。不要相信其中一個方案比另一個好的說法,因為並不總是這樣的。

3、高速緩沖

與訪問(真正的)的內存相比,磁盤[3]的讀寫是很慢的。另外,在相應較短的時間內多次讀磁盤同樣的部分也是常有的事。例如,某人也許首先閱讀了一段e-mail消息,然後為了答復又將這段消息讀入編輯器中,然後又在將這個消息拷貝到文件夾中時,使得郵件程序又一次讀入它。或者考慮一下在一個有著許多用戶的系統中ls命令會被使用多少次。通過將信息從磁盤上僅讀入一次並將其存於內存中,除了第一次讀以外,可以加快所有其它讀的速度。這叫作磁盤緩沖(disk buffering),被用作此目的的內存稱為高速緩沖(buffer cache)。

不幸的是,由於內存是一種有限而又不充足的資源,高速緩沖不可能做的很大(它不可能包容要用到的所有數據)。當緩沖充滿了數據時,其中最長時間不用的數據將被捨棄以騰出內存空間用於新的數據。

對寫磁盤操作來說磁盤緩沖技術同樣有效。一方面,被寫入磁盤的數據常常會很快地又被讀出(例如,原代碼文件被保存到一個文件中,又被編譯器讀入),所以將要被寫的數據放入緩沖中是個好主意。另一方面,通過將數據放入緩沖中,而不是將其立刻寫入磁盤,程序可以加快運行的速度。以後,寫的操作可以在後台完成,而不會拖延程序的執行。

大多數操作系統都有高速緩沖(盡管可能稱呼不同),但是並不是都遵守上面的原理。有些是直接寫(write-through):數據將被立刻寫入磁盤(當然,數據也被放入緩存中)。如果寫操作是在以後做的,那麼該緩存被稱為後台寫(write-back)。後台寫比直接寫更有效,但也容易出錯:如果機器崩潰,或者突然掉電,或者是軟盤在緩沖中等待寫的數據被寫入軟盤之前被從驅動器中取走,緩沖中改變過的數據就被丟失了。如果仍未被寫入的數據含有重要的薄記信息,這甚至可能意味著文件系統(如果有的話)已不完整。

由於上述原因,在使用適當的關閉過程之前,絕對不要關掉電源(見第六章),不要在卸載(如果已被加載)之前將軟盤從驅動器中取出來,也不要在任何正在使用軟盤的程序指示出完成了軟盤操作並且軟盤燈熄滅之前將軟盤取出來。sync命令傾空(flushes)緩沖,也即,強迫所有未被寫的數據寫入磁盤,可用以確定所有的寫操作都已完成。在傳統的UNIX系統中,有一個叫做update的程序運行於後台,每隔30秒做一次sync操作,因此通常無需手工使用sync命令了。Linux另外有一個後台程序,bdflush,這個程序執行更頻繁的但不是全面的同步操作,以避免有時sync的大量磁盤I/O操作所帶來的磁盤的突然凍結。

在Linux中,bdflush是由update啟動的。通常沒有理由來擔心此事,但如果由於某些原因bdflush進程死掉了,內核會對此作出警告,此時你就要手工地啟動它了(/sbin/update)。

緩存(cache)實際並不是緩沖文件的,而是緩沖塊的,塊是磁盤I/O操作的最小單元(在Linux中,它們通常是1KB)。這樣,目錄、超級塊、其它文件系統的薄記數據以及非文件系統的磁盤數據都可以被緩沖了。

緩沖的效力主要是由它的大小決定的。緩沖大小太小的話等於沒用:它只能容納一點數據,因此在被重用時,所有緩沖的數據都將被傾空。實際的大小依賴於數據讀寫的頻次、相同數據被訪問的頻率。只有用實驗的方法才能知道。

如果緩存有固定的大小,那麼緩存太大了也不好,因為這會使得空閒的內存太小而導致進行交換操作(這同樣是慢的)。為了最有效地使用實際內存,Linux自動地使用所有空閒的內存作為高速緩沖,當程序需要更多的內存時,它也會自動地減小緩沖的大小。

在Linux中,你不需要為使用緩沖做任何事情,它是完全自動處理的。除了上面所提到的有關按照適當的步驟來關機和取出軟盤,你不用擔心它。

本文URL:http://www.bianceng.cn/OS/Linux/201410/45613.htm

Copyright © Linux教程網 All Rights Reserved