性能測試必備知識(10)- Linux 是怎麼管理內存的?

作性能測試的必備知識系列,能夠看下面連接的文章哦html

https://www.cnblogs.com/poloyy/category/1806772.html算法

 

內存映射

平常生活常說的內存是什麼

  • 比方說,個人筆記本電腦內存就是 8GB 的
  • 這個內存實際上是物理內存
  • 物理內存也稱爲主存,大多數計算機用的主存都是動態隨機訪問內存(DRAM)

 

靈魂拷問

只有內核才能夠直接訪問物理內存,那麼進程要訪問內存時,怎麼辦?緩存

 

虛擬地址空間

  • 爲了解決上面的問題,Linux 內核給每一個進程都提供了一個獨立的虛擬地址空間,而且這個地址空間是連續
  • 這樣,進程就能夠很方便地訪問內存,更確切地說是訪問虛擬內存

 

內部

  • 虛擬地址空間的內部又被分爲內核空間用戶空間兩部分
  • 不一樣字長(單個 CPU 指令能夠處理數據的最大長度)的處理器,地址空間的範圍也不一樣

 

最多見的 32 位和64 位系統的虛擬地址空間

  • 32 位系統的內核空間佔用 1G,位於最高處,剩下的 3G 是用戶空間
  • 而 64 位系統的內核空間和用戶空間都是 128T,分別佔據整個內存空間的最高和最低處,剩下的中間部分是未定義的

 

進程的用戶態和內核態

  • 進程在用戶態時,只能訪問用戶空間內存
  • 只有進入內核態後,才能夠訪問內核空間內存
  • 雖然每一個進程的地址空間都包含了內核空間,但這些內核空間,其實關聯的都是相同的物理內存
  • 這樣,進程切換到內核態後,就能夠很方便地訪問內核空間內存

 

爲何會有內存映射

  • 既然每一個進程都有一個這麼大的地址空間,那麼全部進程的虛擬內存加起來,天然要比實際的物理內存大得多
  • 因此,並非全部的虛擬內存都會分配物理內存,只有那些實際使用的虛擬內存才分配物理內存
  • 而且分配後的物理內存,是經過內存映射來管理的

 

什麼是內存映射

  • 內存映射,其實就是將虛擬內存地址映射到物理內存地址
  • 爲了完成內存映射,內核爲每一個進程都維護了一張頁表,記錄虛擬地址與物理地址的映射關係

  • 頁表實際上存儲在 CPU 的內存管理單元 MMU
  • 正常狀況下,處理器就能夠直接經過硬件,找出要訪問的內存
  • 在頁表的映射下,進程就能夠經過虛擬地址來訪問物理內存了

 

靈魂拷問

麼具體到 一個 Linux 進程中,這些內存又是怎麼使用的呢?ssh

 

 

虛擬內存空間分佈

回答上面的問題,須要進一步瞭解虛擬內存空間的分佈狀況函數

用戶空間內存,其實又被分紅了多個不一樣的段性能

這是 32 位系統,用戶空間內存,從低到高分別是五種不一樣的內存段測試

  1. 只讀段:包括代碼和常量等
  2. 數據段:包括全局變量等
  3. 堆:包括動態分配的內存,從低地址開始向上增加
  4. 文件映射段:包括動態庫、共享內存等,從高地址開始向下增加
  5. 棧:包括局部變量和函數調用的上下文等。棧的大小是固定的,通常是 8 MB

 

在這五個內存段中,堆和文件映射段的內存是動態分配spa

好比說,使用 C 標準庫的 malloc()  或者 mmap() ,就能夠分別在堆和文件映射段動態分配內存code

 

其實 64 位系統的內存分佈也相似,只不過內存空間要大得多htm

 

靈魂拷問

內存到底是怎麼分配的呢?

 

內存分配與回收

分配

 malloc() 是 C 標準庫提供的內存分配函數,對應到系統調用上,有兩種實現方式,即 brk() 和 mmap() 

 

brk()

  • 對小塊內存(小於 128K),C 標準庫使用 brk() 來分配
  • 也就是經過移動堆頂的位置來分配內存
  • 這些內存釋放後並不會馬上歸還系統,而是被緩存起來,這樣就能夠重複使用
  • 優勢:緩存能夠減小缺頁異常的發生,提升內存訪問效率
  • 缺點:因爲這些內存沒有歸還系統,在內存工做繁忙時,頻繁的內存分配和釋放會形成內存碎片

 

mmap()

  • 大塊內存(大於 128K),則直接使用內存映射 mmap() 來分配,也就是在文件映射段找一塊空閒內存分配出去
  • 缺點:分配的內存,會在釋放時直接歸還系統,因此每次 mmap 都會發生缺頁異常;在內存工做繁忙時,頻繁的內存分配會致使大量的缺頁異常,使內核的管理負擔增大, 這也是 malloc 只對大塊內存使用 mmap 的緣由

 

總結

  • 當這兩種調用發生後,其實並無真正分配內存
  • 這些內存,都只在首次訪問時才分配,也就是經過缺頁異常進入內核中,再由內核來分配內存

 

Linux 使用夥伴系統來管理內存分配

  • 這些內存在 MMU 中以頁爲單位進行管理,夥伴系統也同樣,以頁爲單位來管理內存,而且會經過相鄰頁的合併,減小內存碎片化
  • 在用戶空間,malloc 經過 brk() 分配的內存,在釋放時並不當即歸還系統,而是緩存起來重複利用
  • 在內核空間,Linux 則經過 slab 分配器來管理小內存
  • 你能夠把 slab 當作構建在夥伴系統上的一個緩存,主要做用就是分配並釋放內核中的小對象

 

釋放內存

  • 對內存來講,若是隻分配而不釋放,就會形成內存泄露,甚至會耗盡系統內存
  • 因此,在應用程序用完內存後,還須要調用 free() 或 unmap() ,來釋放這些不用的內存

 

回收

系統不會任由某個進程用完全部內存,在發現內存緊張時,系統就會經過一系列機制來回收內存

  1. 回收緩存:好比使用 LRU(Least Recently Used)算法,回收最近使用最少的內存頁面
  2. 回收不常訪問的內存:把不經常使用的內存經過交換分區直接寫到磁盤中
  3. 殺死進程:內存緊張時系統還會經過 OOM(Out of Memory),直接殺掉佔用大量內存的進程

 

回收不常訪問的內存

  • 會用到交換分區(如下簡稱 Swap
  • Swap 其實就是把一塊磁盤空間當成內存來用
  • 它能夠把進程暫時不用的數據存儲到磁盤中(這個過程稱爲換出),當進程訪問這些內存時,再從磁盤讀取這些數據到內存中(這個過程稱爲換入
  • 一般只在內存不足時, 纔會發生 Swap 交換
  • 優勢:Swap 把系統的可用內存變大了
  • 缺點:因爲磁盤讀寫的速度遠比內存慢,因此 Swap 會致使嚴重的內存性能問題

 

OOM

是內核的一種保護機制

監控進程的內存使用狀況,而且使用 oom_score 爲每一個進程的內存使用狀況進行評分:

  • 一個進程消耗的內存越大,oom_score 就越大,越容易被 OOM 殺死,從而保護系統
  • 一個進程運行佔用的 CPU 越多,oom_score 就越小

 

能夠經過 /proc 文件系統,手動設置進程的  oom_adj ,從而調整進程的 oom_score 

 oom_adj  的範圍是 [-17, 15] ,數值越大,表示進程越容易被 OOM 殺死;數值越小,表示進程越不容易被 OOM 殺死,其中 -17 表示禁止 OOM

 

調整 oom_score 的栗子

把 sshd 進程的 oom_adj 調小爲 -16,這樣, sshd 進程就 不容易被 OOM 殺死

echo -16 > /proc/$(pidof sshd)/oom_adj 

 

如何查看內存使用狀況

free

顯示的是整個系統的內存使用狀況

http://www.javashuo.com/article/p-zwjwyhmi-mh.html

 

top

能夠查看系統內存使用狀況,也能夠看進程的,具體能夠看下面的博客哦

http://www.javashuo.com/article/p-wmedtlay-mh.html

相關文章
相關標籤/搜索