How Linux Works(三):內存管理

摘要

  • 經典內存異常:Out of Memory (OOM) Killer
  • 我的內存利用率為什麼特別高?
  • Linux 內存的分類
  • Linux 內存的計算
  • Linux 進程的內存
  • Linux 應用內存分配

內存是計算機中與CPU進行溝通的橋樑,用於暫時存放CPU中的運算數據。Linux 內核的內存管理機制設計得非常精妙,對於 Linux 內核的性能有很大影響。在早期的 Unix 系統中,fork 啟動新進程時,由於從父進程往子進程複製內存信息需要消耗一定的時間,因此啟動多個進程時存在性能瓶頸。現在的 Linux 內核則通過「寫時複製(copy-on-write)」等機制提高了創建進程的效率;也正是因為這個原因,關於 Linux 內存分配、計算、空閑判斷有一些特別的地方需要注意。

內存異常: Out of Memory (OOM) Killer

最常見的內存管理異常就是 Out of memory 問題。通常是因為某個應用程序大量請求內存導致系統內存不足造成的,觸發 Linux 內核里的 Out of Memory (OOM) killer,OOM killer 會殺掉某個進程以釋放內存留給系統內核用。它實際上算一種保護機制,不致於讓系統立刻崩潰,有些壯士斷腕的意思。

內核檢測到內存利用不足,就會選擇並殺掉某個「bad」進程。如何判斷和選擇一個 「bad」 進程呢? 演算法和思路其實非常樸素(簡單):最 bad 的那個進程就是那個佔用內存最多的進程。內核源代碼詳見 linux/mm/oom_kill.c 。

我的內存利用率為什麼特別高?

  • 內存利用率(概括): free
  • 內存利用率(進程): top

實際情況是系統運行正常、不存在內存不足的情況,對於應用程序來說,「真實的」 內存空閑率是 73.4% 。如果要回答這個問題,必須了解內存管理的基礎 —— 物理地址空間和邏輯地址空間。

按照用途,內存可以劃分為「內核內存」和「用戶內存」(用戶進程及磁碟高速緩存),包括內核本身在內,程序在訪問物理內存時,並不直接指定物理地址,而是指定邏輯地址。CPU 上搭載的硬體 MMU (Memory Management Unit)會參照物理-邏輯地址對應關係表實現對映射後物理地址上的數據訪問。x86 架構中邏輯地址空間限制在 4GB ,在 x86_64 架構中則沒有此限制。

Linux 內存的分類

用戶內存的分類有兩組概念比較重要:匿名內存和File-backed內存;Active 和 Inactive 。它們的區別如下:

  • 匿名內存:用來存儲用戶進程計算過程中間的數據,與物理磁碟的文件沒有關係;
  • File-backed內存:用作磁碟高速緩存,其物理內存與物理磁碟上的文件是對應的;
  • Active : 剛被使用過的數據的內存空間;
  • Inactive : 包含有長時間未被使用過的數據的內存空間;

Shmem(shared memory)指的就是 tmpfs 所使用的內存 —— 一個基於內存的文件系統,提供可以接近零延遲的快速存儲區域。Linux 可以將空閑內存用於緩存,並且在應用程序需要的時候收回。「-/+ buffers/cache」: 提供了關於內存利用率更加準確的數值。buffers: buffer cache,用於塊設備I/O ; cached: page cache, 用於文件系統。例如:

  • 內存利用率(詳細):cat /proc/meminfo

Linux 內存的計算

各類內存的計算公式如下:

Shmem = 磁碟高速緩存(buffers/cached)- Filed-backed內存(file)

= 匿名內存(anon)- AnonPages

用戶內存 = Active(file) + Inactive(file) + Active(anon) + Inactive(anon) + Unevictable

= buffers + cached + AnonPages

內核內存 = Memtotal - (MemFree + Active + Inactive + Unevictable)

Linux 進程的內存

執行「ps aux」 後輸出的各進程的 RSS (resident set size), 表示進程佔用內存的大小,單位是KB。 需要注意的是,RSS 值實際上是基於 pmap 命令,表示「該進程正在使用的物理內存的總和」。pmap 提供了進程的內存映射,也可以支持多個進程的內存狀態顯示(pmap pid1 pid2 pid3)。與 ldd 命令類似,pmap 命令可以查看到程序調用的路徑。如果查看一個已經運行,但是又不知道程序路徑的程序,使用pmap更快捷。

/proc/PID/status 支持的選項有:

  • VmData: data段大小
  • VmExe: text段大小
  • Vmlib: 共享庫的使用量
  • VmRSS: 物理內存使用量
  • VmSwap: 交換空間的使用量

Linux 應用內存分配

類似 Java 之類的虛擬機應用程序可以設置內存參數,例如:

Xms128m JVM初始分配的堆內存

Xmx512m JVM最大允許分配的堆內存

XX:PermSize=64M JVM初始分配的非堆內存

XX:MaxPermSize=128M JVM最大允許分配的非堆內存

如果該應用需要較大的內存空間,可以調整為 -Xmx1024m、-Xmx2048m 以保障應用程序的運行性能,XX:MaxPermSize 設置過小會導致內存溢出,java.lang.OutOfMemoryError: PermGen space。但是 需要特別注意 的是:Xmx 絕對不能超過最大物理內存,或者說需要保留一定的剩餘內存空間,否則將有可能導致其它進程因為沒有可用內存而阻塞,甚至無法登陸機器 。

正如摔跤遊戲一樣,內存管理的法則就是讓進程在 留有餘地 的前提下搏殺。

擴展閱讀:Linux 操作系統

  • 《Linus Torvalds:Just for Fun》
  • Linux 常用命令一百條
  • Linux 性能診斷:負載評估
  • Linux 性能診斷:快速檢查單(Netflix版)
  • Linux 性能診斷:薦書|《圖解性能優化》
  • Linux 性能診斷:Web應用性能優化
  • 操作系統原理 | How Linux Works(一):How the Linux Kernel Boots
  • 操作系統原理 | How Linux Works(二):User Space & RAM
  • 操作系統原理 | How Linux Works(三):Memory

推薦:電子書《Linux Perf Master》

發表在GitBook平台,歡迎訂閱、下載、批評指正: gitbook.com/book/ribose


推薦閱讀:

YunOS 與 Android 有什麼關係?
Linux內核中許多晶元的驅動程序都已經存在,為何還要開發這些晶元的驅動?
Linux 學習歷程 ?
Linux哪種文件系統更有前景?
Linux下的timerfd在OS X下可以用什麼替代?

TAG:Linux | 性能分析 | 操作系统 |