記憶體是Linux核心所管理的最重要的資源之一,記憶體管理系統是作業系統中最為重要的部分。對於Linux的初學者來說,熟悉Linux的記憶體管理非常重要。
進程是運行於虛擬位址空間的一個程式。可以說,任何在Linux系統下啟動並執行程式都是進程。Linux系統中包括互動進程和批處理進程。互動進程是由Shell控制和啟動並執行,既可以在前台運行,也可以在後台運行。批處理進程不屬於某個終端,被提交到一個隊列中以便順序執行。大多數的進程都需要虛擬記憶體。
一般需要多少記憶體
對於典型的Linux應用系統,128MB記憶體是合理的選擇。如果不運行X-Window系統,那麼在一台特殊用途的機器(比如用於調試裝置驅動程式的“崩潰和燒毀”系統)上僅用8MB記憶體就可以工作。
筆者曾經做過實驗,在128MB和256MB下編譯核心所需的時間幾乎一樣,都少於3分半鐘(筆者的Linux發行版本是Mandrake Linux 9.1,核心2.4.21)。在一個只有8MB記憶體的系統上,編譯需要的時間會更長一些。類似Web瀏覽器這樣的多媒體應用軟體,在記憶體充足時會運行得更流暢,特別是在一邊編譯器,一邊上網瀏覽的時候更是如此。因此,如果只有128MB記憶體,則預期的效能會有所降低。類似地,如果要開發消耗大量記憶體的應用程式,可能會要求更多的記憶體。所以,需要多少記憶體由工作需求來決定。
即時監控記憶體使用量情況
1.在命令列使用“Free”命令監控記憶體使用量情況
#free
total used free shared buffers cached
Mem: 256024 192284 63740 0 10676 101004
-/+ buffers/cache: 80604 75420
Swap: 522072 0 522072
上面代碼給出了一個256MB的RAM和512MB交換空間的系統情況。第三行輸出(Mem:)顯示實體記憶體。Total列不顯示核心使用的實體記憶體(通常大約1MB)。Used列顯示被使用的記憶體總額(第二行不計緩衝)。Free列顯示全部沒有使用的記憶體。Shared列顯示多個進程共用的記憶體總額。Buffers列顯示磁碟緩衝的當前大小。第五行(Swap:)對換空間,顯示的資訊類似上面。如果這行為全0,那麼就沒有使用對換空間。在預設的狀態下,free命令以KB(也就是1024位元組為單位)來顯示記憶體使用量情況。使用-h參數,以位元組為單位顯記憶體使用量情況;或者使用-m參數,以MB為單位顯示記憶體使用量情況。還可以通過-s參數,使用命令來不間斷地監視記憶體使用量情況:
#free -b -s5
這個命令將會在終端視窗中連續不斷地報告記憶體的使用方式,每5秒鐘更新一次。
2.使甩vmstat命令監視虛擬記憶體使用方式
# vmstat
procs -----------memory---------- ---swap-- -----io---- --system-- ----cpu----
r b swpd free buff cache si so bi bo in cs us sy id wa
1 0 0 63692 10704 101008 0 0 239 42 126 105 48 45 7 0
vmstat()命令是一個通用監控程式,是Virtual Meomory Statistics(虛擬記憶體統計)的縮寫。如果使用vmstat命令的時候沒有使用任何命令列參數,將會得到一個一次性的報告。vmstat命令報告主要的活動類型有進程(procs)、記憶體(以KB為單位)、交換分區(以KB為單位)、來自塊裝置(硬碟)的輸入輸出量、系統中斷(每秒鐘發生的次數),以及中央處理單元(CPU)分配給使用者、系統和空閑時分別佔用的比例。
虛擬記憶體實現的機制
儲存管理子系統是作業系統中最重要的組成部分之一。在早期計算時代,由於人們所需要的記憶體數目遠遠大於實體記憶體,因此設計出了各種各樣的策略來解決此問題,其中最成功的就是虛擬記憶體技術,它使得系統中有限的實體記憶體競爭進程所需記憶體空間得到滿足。虛擬記憶體通過在各個進程之間共用記憶體,而使系統看起來有多於實際記憶體的記憶體容量。Linux支援虛擬記憶體, 就是使用磁碟作為RAM的擴充,使可用記憶體相應地有效擴大。核心把當前不用的記憶體塊存到硬碟,騰出記憶體給其它目的。當原來的內容又要使用時,再讀回記憶體。運行於Linux的程式只看到大量的可用記憶體,而不關心哪部分在磁碟上。當然,讀寫硬碟比真的記憶體慢(大約慢千倍),所以程式運行較慢。用做虛擬記憶體的這部分硬碟叫對換空間。
虛擬記憶體技術不僅僅讓我們可以使用更多的記憶體,它還提供了下面這些功能:
1.巨大的定址空間
作業系統讓系統看上去有比實際記憶體大得多的記憶體空間。虛擬記憶體可以是系統中實際物理空間的許多倍。每個進程運行在其獨立的虛擬位址空間中,這些虛擬空間相互之間都完全隔離開來,所以進程間不會互相影響。同時,硬體虛擬記憶體機構可以將記憶體的某些地區設定成不可寫,這樣可以保護代碼與資料不會受惡意程式的幹擾。
2.公平的實體記憶體分配
記憶體管理子系統允許系統中每個啟動並執行進程公平地共用系統中的實體記憶體。
3.共用虛擬記憶體
儘管虛擬記憶體允許進程有其獨立的虛擬位址空間,但有時也需要在進程之間共用記憶體。例如,有可能系統中有幾個進程同時運行BASH命令外殼程式。為了避免在每個進程的虛擬記憶體空間內都存在BASH程式的拷貝,較好的解決辦法是系統實體記憶體中只存在一份BASH的拷貝,並在多個進程間共用。動態庫則是另外一種進程間共用執行代碼的方式。共用記憶體可用來作為處理序間通訊(IPC)的手段,多個進程通過共用記憶體來交換資訊。Linux支援SYSTEM V的共用記憶體IPC機制。
4.進程的保護
系統中的每一個進程都有自己的虛擬位址空間。這些虛擬位址空間是完全分開的,這樣一個進程的運行不會影響其它進程,並且硬體上的虛擬記憶體機制是被保護的,記憶體不能被寫入。這樣可以防止迷失的應用程式覆蓋代碼的資料。
5.Linux虛擬記憶體實現機制
Linux虛擬記憶體的實現需要6種機制的支援:地址映射機制、記憶體配置回收機制、緩衝和重新整理機制、請求頁機制、交換器制和記憶體共用機制。
記憶體管理程式通過映射機制把使用者程式的邏輯地址映射到物理地址。當使用者程式運行時,如果發現程式中要用的虛地址沒有對應的實體記憶體,就發出了請求頁要求。如果有閒置記憶體可供分配,就請求分配記憶體(於是用到了記憶體的分配和回收),並把正在使用的物理頁記錄在緩衝中(使用了緩衝機制)。如果沒有足夠的記憶體可供分配,那麼就調用交換器制;騰出一部分記憶體。另外,在地址映射中要通過TLB(翻譯後援儲存空間)來尋找物理頁;交換器制中也要用到交換緩衝,並且把物理頁內容交換到分頁檔中,也要修改頁表來對應檔地址。Linux虛擬記憶體實現原理見圖1。
<img src="http://tech.ccidnet.com/pub/attachment/2004/10/347128.jpg">
圖1 Linux虛擬記憶體實現原理
6.虛擬記憶體容量設定
也許有人說,虛擬記憶體容量的設定應該分配2倍於實體記憶體,但這隻是個規律。如果實體記憶體比較小,可以這樣設定。如果有256MB實體記憶體或更多的話,就可以縮小虛擬記憶體。Linux會把大量的記憶體用做Cache,但在資源緊張時會收回。只要看到swap為0,或者該數很小就可以放心了,記憶體放著不用才是最大的浪費。
記憶體泄露和回收記憶體的方法
1.記憶體流失的定義
一般常說的記憶體流失是指堆記憶體的泄漏。堆記憶體是指程式從堆中分配的、大小任意的(記憶體塊的大小可以在程式運行期決定)、使用完後必須顯示釋放的記憶體。應用程式一般使用malloc、realloc、new等函數從堆中分配到一塊記憶體,使用完後,程式必須負責相應的調用free或delete釋放該記憶體塊。否則,這塊記憶體就不能被再次使用,我們就說這塊記憶體流失了。
2.記憶體泄露的危害
從使用者使用程式的角度來看,記憶體流失本身不會產生什麼危害。作為一般的使用者,根本感覺不到記憶體流失的存在。真正有危害的是記憶體流失的堆積,這會最終消耗盡系統所有的記憶體。從這個角度來說,一次性記憶體流失並沒有什麼危害,因為它不會堆積。而隱式記憶體流失危害性則非常大,因為較之於常發性和偶發性記憶體流失它更難被檢測到。存在記憶體流失問題的程式除了會佔用更多的記憶體外,還會使程式的效能急劇下降。對於伺服器而言,如果出現這種情況,即使系統不崩潰,也會嚴重影響使用。
3.記憶體泄露的檢測和回收
對於記憶體溢出之類的麻煩,大家可能在編寫指標比較多的複雜程式時就會遇到。在Linux或Unix下,C和C++語言是最常使用的工具。但是C++程式缺乏相應的手段來檢測記憶體資訊,只能使用top指令觀察進程的動態記憶體總額。而且程式退出時,我們無法獲知任何記憶體流失資訊。
(1)使用Linux命令回收記憶體,可以使用ps、kill兩個命令檢測記憶體使用量情況和進行回收。在使用超級使用者權限時使用命令“ps”,它會列出所有正在啟動並執行程式名稱和對應的進程號(PID)。kill命令的工作原理是向Linux作業系統的核心送出一個系統操作訊號和程式的進程號(PID)。
下面舉例說明,為了高效率回收記憶體可以使用命令ps參數v:
#ps v
PID TTY STAT TIME MAJFL TRS DRS RSS %MEM COMMAND
2530 vc/1 S 0:00 104 6 1325 408 0.1 /sbin/mingetty tty1
2531 vc/2 S 0:00 104 6 1325 408 0.1 /sbin/mingetty tty2
2532 vc/3 S 0:00 104 6 1325 408 0.1 /sbin/mingetty tty3
2533 vc/4 S 0:00 104 6 1325 408 0.1 /sbin/mingetty tty4
2534 vc/5 S 0:00 104 6 1325 408 0.1 /sbin/mingetty tty5
2535 vc/6 S 0:00 104 6 1325 408 0.1 /sbin/mingetty tty6
2639 pts/1 S 0:00 545 16 2643 968 0.3 [su]
2684 pts/1 S 0:00 361 586 2501 1592 0.6 bash
2711 pts/0 S 0:00 545 16 2643 968 0.3 [su]
2714 pts/0 S 0:00 361 586 2501 1592 0.6 bash
2754 pts/2 S 0:00 545 16 2643 968 0.3 [su]
2757 pts/2 S 0:00 361 586 2501 1592 0.6 bash
2818 pts/1 S 0:00 120 29 1478 480 0.1 ping 192.168.1.7
2939 pts/2 R 0:00 156 58 2469 644 0.2 ps -v
如果想回收ping命令的記憶體的話,可以使用下面命令:
# kill -9 2818
(2)使用工具軟體
Memprof是一個非常具有吸引力且便於使用的軟體,它由Red Hat的Owen Talyor創立。這個工具用於GNOME前端的Boehm-Demers-Weiser記憶體回收行程。這個工具直接就可以執行,並且其工作起來無需對原始碼進行任何修改。在程式執行時,這個工具會以圖形化的方式顯示記憶體的使用方式,工作介面見圖2。
<img src="http://tech.ccidnet.com/pub/attachment/2004/10/347130.jpg">
圖2 記憶體回收工具Memprof
但是,該工具目前只能運行於x86和PPC體繫結構的Linux系統之中,需要一個完整的GNOME環境。這樣就使得其不能靈活用於所有的地方。此外,該工具的開發工作進展得也比較緩慢,現在是0.5.1版。
上面講述了Linux記憶體的概念、需要多少記憶體、即時監控記憶體使用量情況、虛擬記憶體實現的機制,以及記憶體泄露和回收方法等五個方面內容,希望能對Linux初學者高效率使用記憶體系統有所協助.