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平台,歡迎訂閱、下載、批評指正: https://www.gitbook.com/book/riboseyim/linux-perf-master/details
推薦閱讀:
※YunOS 與 Android 有什麼關係?
※Linux內核中許多晶元的驅動程序都已經存在,為何還要開發這些晶元的驅動?
※Linux 學習歷程 ?
※Linux哪種文件系統更有前景?
※Linux下的timerfd在OS X下可以用什麼替代?