30% 的 RAM 是“緩衝區”。它是什麼?
如何在輸出中描述或解釋“緩衝區”
free
?$ free -h total used free shared buff/cache available Mem: 501M 146M 19M 9.7M 335M 331M Swap: 1.0G 85M 938M $ free -w -h total used free shared buffers cache available Mem: 501M 146M 19M 9.7M 155M 180M 331M Swap: 1.0G 85M 938M
我對這個系統沒有任何(已知的)問題。我很驚訝和好奇地看到“緩衝區”幾乎和“記憶體”一樣高(155M vs 180M)。我認為“記憶體”代表文件內容的頁面記憶體,並且往往是“記憶體/緩衝區”中最重要的部分。我不確定什麼是“緩衝區”。
例如,我將此與具有更多 RAM 的筆記型電腦進行了比較。在我的筆記型電腦上,“緩衝區”數字比“記憶體”(200M 與 4G)小一個數量級。如果我了解“緩衝區”是什麼,那麼我可以開始研究為什麼緩衝區在較小的系統上增長到如此大的比例。
來自
man proc
(我忽略了“大”的可笑過時的定義):緩衝區 %lu
用於不應該變得非常大(20MB 左右)的原始磁碟塊的相對臨時儲存。
記憶體的%lu
從磁碟讀取的文件的記憶體記憶體(頁面記憶體)。不包括 SwapCached。
$ free -V free from procps-ng 3.3.12 $ uname -r # the Linux kernel version 4.9.0-6-marvell $ systemd-detect-virt # this is not inside a virtual machine none $ cat /proc/meminfo MemTotal: 513976 kB MemFree: 20100 kB MemAvailable: 339304 kB Buffers: 159220 kB Cached: 155536 kB SwapCached: 2420 kB Active: 215044 kB Inactive: 216760 kB Active(anon): 56556 kB Inactive(anon): 73280 kB Active(file): 158488 kB Inactive(file): 143480 kB Unevictable: 10760 kB Mlocked: 10760 kB HighTotal: 0 kB HighFree: 0 kB LowTotal: 513976 kB LowFree: 20100 kB SwapTotal: 1048572 kB SwapFree: 960532 kB Dirty: 240 kB Writeback: 0 kB AnonPages: 126912 kB Mapped: 40312 kB Shmem: 9916 kB Slab: 37580 kB SReclaimable: 29036 kB SUnreclaim: 8544 kB KernelStack: 1472 kB PageTables: 3108 kB NFS_Unstable: 0 kB Bounce: 0 kB WritebackTmp: 0 kB CommitLimit: 1305560 kB Committed_AS: 1155244 kB VmallocTotal: 507904 kB VmallocUsed: 0 kB VmallocChunk: 0 kB $ sudo slabtop --once Active / Total Objects (% used) : 186139 / 212611 (87.5%) Active / Total Slabs (% used) : 9115 / 9115 (100.0%) Active / Total Caches (% used) : 66 / 92 (71.7%) Active / Total Size (% used) : 31838.34K / 35031.49K (90.9%) Minimum / Average / Maximum Object : 0.02K / 0.16K / 4096.00K OBJS ACTIVE USE OBJ SIZE SLABS OBJ/SLAB CACHE SIZE NAME 59968 57222 0% 0.06K 937 64 3748K buffer_head 29010 21923 0% 0.13K 967 30 3868K dentry 24306 23842 0% 0.58K 4051 6 16204K ext4_inode_cache 22072 20576 0% 0.03K 178 124 712K kmalloc-32 10290 9756 0% 0.09K 245 42 980K kmalloc-96 9152 4582 0% 0.06K 143 64 572K kmalloc-node 9027 8914 0% 0.08K 177 51 708K kernfs_node_cache 7007 3830 0% 0.30K 539 13 2156K radix_tree_node 5952 4466 0% 0.03K 48 124 192K jbd2_revoke_record_s 5889 5870 0% 0.30K 453 13 1812K inode_cache 5705 4479 0% 0.02K 35 163 140K file_lock_ctx 3844 3464 0% 0.03K 31 124 124K anon_vma 3280 3032 0% 0.25K 205 16 820K kmalloc-256 2730 2720 0% 0.10K 70 39 280K btrfs_trans_handle 2025 1749 0% 0.16K 81 25 324K filp 1952 1844 0% 0.12K 61 32 244K kmalloc-128 1826 532 0% 0.05K 22 83 88K trace_event_file 1392 1384 0% 0.33K 116 12 464K proc_inode_cache 1067 1050 0% 0.34K 97 11 388K shmem_inode_cache 987 768 0% 0.19K 47 21 188K kmalloc-192 848 757 0% 0.50K 106 8 424K kmalloc-512 450 448 0% 0.38K 45 10 180K ubifs_inode_slab 297 200 0% 0.04K 3 99 12K eventpoll_pwq 288 288 100% 1.00K 72 4 288K kmalloc-1024 288 288 100% 0.22K 16 18 64K mnt_cache 287 283 0% 1.05K 41 7 328K idr_layer_cache 240 8 0% 0.02K 1 240 4K fscrypt_info
- “緩衝區”和其他類型的記憶體有什麼區別?
- 為什麼這種區別如此突出?為什麼有些人在談論記憶體文件內容時會說“緩衝區記憶體”?
- 是
Buffers
用來做什麼的?- 為什麼我們
Buffers
特別期望更大或更小?1.“緩衝區”與其他類型的記憶體有什麼區別?
Buffers
顯示用於塊設備的頁面記憶體量。“塊設備”是最常見的數據儲存設備類型。核心在報告時必須故意從頁面記憶體的其餘部分中減去這個數量
Cached
。見meminfo_proc_show():cached = global_node_page_state(NR_FILE_PAGES) - total_swapcache_pages() - i.bufferram; ... show_val_kb(m, "MemTotal: ", i.totalram); show_val_kb(m, "MemFree: ", i.freeram); show_val_kb(m, "MemAvailable: ", available); show_val_kb(m, "Buffers: ", i.bufferram); show_val_kb(m, "Cached: ", cached);
2. 為什麼這種區別如此突出?為什麼有些人在談論記憶體文件內容時會說“緩衝區記憶體”?
頁面記憶體以 MMU 頁面大小為單位工作,通常至少為 4096 字節。這是必不可少的
mmap()
,即記憶體映射文件訪問。$$ 1 $$$$ 2 $$ 它旨在在不同程序之間共享已載入程序/庫程式碼的頁面,並允許按需載入各個頁面。(也用於在其他需要空間且最近未使用過的頁面時解除安裝頁面)。 $$ 1 $$ 記憶體映射 I/O - GNU C 庫手冊。
$$ 2 $$
mmap
- 維基百科。早期的 UNIX 有一個磁碟塊的“緩衝區記憶體”,並且沒有 mmap()。顯然,當首次添加 mmap() 時,他們將頁面記憶體添加為頂部的新層。這聽起來很混亂。最終,基於 UNIX 的作業系統擺脫了單獨的緩衝區記憶體。所以現在所有的文件記憶體都是以頁面為單位的。頁面是通過(文件,偏移量)而不是磁碟上的位置來查找的。這被稱為“統一緩衝區記憶體”,可能是因為人們更熟悉“緩衝區記憶體”。
$$ 3 $$ $$ 3 $$ UBC:用於 NetBSD 的高效統一 I/O 和記憶體記憶體子系統
(“Linux 添加的一個有趣的轉折是,將頁面儲存在磁碟上的設備塊號以
buffer_head
結構列表的形式與頁面一起記憶體。當修改的頁面要寫回磁碟時,I/ O 請求可以立即發送到設備驅動程序,無需讀取任何間接塊來確定頁面數據應寫入的位置。”$$ 3 $$) 在 Linux 2.2 中,有一個單獨的“緩衝區記憶體”用於寫入,但不用於讀取。“頁面記憶體使用緩衝區記憶體寫回其數據,需要額外的數據副本,並且某些寫入負載的記憶體需求增加了一倍”。
$$ 4 $$ 讓我們不要太擔心細節,但這段歷史將是 Linux
Buffers
單獨報告使用情況的原因之一。 $$ 4 $$ Linux 2.4 記憶體管理中的頁面替換,Rik van Riel。相比之下,在 Linux 2.4 及更高版本中,不存在額外的副本。“系統直接與頁面記憶體頁面進行磁碟 IO。”
$$ 4 $$ Linux 2.4 於 2001 年發布。 3. 有什麼
Buffers
用?塊設備被視為文件,頁面記憶體也是如此。這用於“文件系統元數據和原始塊設備的記憶體”。
$$ 4 $$ 但在目前版本的 Linux 中,文件系統不會通過它複製文件內容,因此沒有“雙重記憶體”。 我認為
Buffers
頁面記憶體的一部分是 Linux 緩衝區記憶體。一些消息來源可能不同意這個術語。文件系統使用多少緩衝區記憶體(如果有)取決於文件系統的類型。問題中的系統使用 ext4。ext3/ext4 使用 Linux 緩衝區記憶體來儲存日誌、目錄內容和其他一些元數據。
某些文件系統,包括 ext3、ext4 和 ocfs2,使用 jbd 或 jbd2 層來處理它們的物理塊日誌,而這一層從根本上使用緩衝區記憶體。
在 Linux 核心版本 2.4 之前,Linux 有單獨的頁面和緩衝區記憶體。從 2.4 開始,頁面和緩衝區記憶體是統一的,並且
Buffers
是未在頁面記憶體中表示的原始磁碟塊——即,不是文件數據。…
但是,緩衝區高速記憶體仍然存在,因為核心仍然需要根據塊而不是頁來執行塊 I/O。由於大多數塊代表文件數據,因此大部分緩衝區記憶體由頁記憶體代表。但是少量塊數據不是文件支持的——例如元數據和原始塊 I/O——因此僅由緩衝區記憶體表示。
– Robert Love的一對 Quora 答案,最後更新於 2013 年。
兩位作者都是從事 Linux 核心記憶體管理工作的 Linux 開發人員。第一個來源更具體地介紹了技術細節。第二個來源是一個更籠統的總結,在某些細節上可能是矛盾的和過時的。
確實,文件系統可以執行部分頁面元數據寫入,即使記憶體是按頁面索引的。甚至使用者程序在使用
write()
(而不是mmap()
)時也可以執行部分頁面寫入,至少直接寫入塊設備。這僅適用於寫入,不適用於讀取。當您讀取頁面記憶體時,頁面記憶體始終讀取完整頁面。Linus 喜歡抱怨緩衝區記憶體對於進行塊大小的寫入不是必需的,並且文件系統可以執行部分頁面元數據寫入,即使頁面記憶體附加到它們自己的文件而不是塊設備。我相信他說 ext2 這樣做是對的。帶有日誌系統的 ext3/ext4 沒有。目前尚不清楚導致這種設計的問題是什麼。他咆哮的人已經厭倦了解釋。
ext4_readdir() 沒有改變以滿足 Linus 的咆哮。我也沒有看到他在其他文件系統的 readdir() 中使用了他想要的方法。我認為 XFS 也將緩衝區記憶體用於目錄。bcachefs 根本不使用 readdir() 的頁面記憶體;它使用自己的 btree 記憶體。我不確定 btrfs。
- 為什麼我們
Buffers
特別期望更大或更小?在這種情況下,我的文件系統的ext4 日誌大小是 128M。所以這就解釋了為什麼 1)我的緩衝區記憶體可以穩定在 128M 以上;2) 緩衝區記憶體與筆記型電腦上較大的 RAM 量不成比例。
有關其他一些可能的原因,請參閱free 輸出中的緩衝區列是什麼? 請注意,報告的“緩衝區”
free
實際上是Buffers
可回收核心平板記憶體的組合。為了驗證日誌寫入使用緩衝區記憶體,我在快速 RAM (tmpfs) 中模擬了一個文件系統,並比較了不同日誌大小的最大緩衝區使用量。
# dd if=/dev/zero of=/tmp/t bs=1M count=1000 ... # mkfs.ext4 /tmp/t -J size=256 ... # LANG=C dumpe2fs /tmp/t | grep '^Journal size' dumpe2fs 1.43.5 (04-Aug-2017) Journal size: 256M # mount /tmp/t /mnt # cd /mnt # free -w -m total used free shared buffers cache available Mem: 7855 2521 4321 285 66 947 5105 Swap: 7995 0 7995 # for i in $(seq 40000); do dd if=/dev/zero of=t bs=1k count=1 conv=sync status=none; sync t; sync -f t; done # free -w -m total used free shared buffers cache available Mem: 7855 2523 3872 551 237 1223 4835 Swap: 7995 0 7995
# dd if=/dev/zero of=/tmp/t bs=1M count=1000 ... # mkfs.ext4 /tmp/t -J size=16 ... # LANG=C dumpe2fs /tmp/t | grep '^Journal size' dumpe2fs 1.43.5 (04-Aug-2017) Journal size: 16M # mount /tmp/t /mnt # cd /mnt # free -w -m total used free shared buffers cache available Mem: 7855 2507 4337 285 66 943 5118 Swap: 7995 0 7995 # for i in $(seq 40000); do dd if=/dev/zero of=t bs=1k count=1 conv=sync status=none; sync t; sync -f t; done # free -w -m total used free shared buffers cache available Mem: 7855 2509 4290 315 77 977 5086 Swap: 7995 0 7995
這個答案的歷史:我是如何看雜誌的
我首先找到了 Ted Tso 的電子郵件,並且對它強調寫記憶體很感興趣。如果“臟”、未寫入的數據能夠達到我係統上 30% 的 RAM, 我會感到驚訝。
sudo atop
顯示在 10 秒的時間間隔內,有問題的系統始終只寫入 1MB。相關的文件系統將能夠跟上這個速度的 100 倍以上。(它位於 USB2 硬碟驅動器上,最大吞吐量約為 20MB/s)。使用 blktrace (
btrace -w 10 /dev/sda
) 確認正在記憶體的 IO 必須是寫入的,因為幾乎沒有數據被讀取。這mysqld
也是唯一執行 IO的使用者空間程序。我停止了負責寫入的服務(icinga2 寫入 mysql)並重新檢查。我看到“緩衝區”下降到 20M 以下 - 我對此沒有任何解釋 - 並留在那裡。再次重新啟動編寫器顯示“緩衝區”每 10 秒間隔上升約 0.1M。我觀察到它一直保持這個速度,回升至 70M 及以上。
執行
echo 3 | sudo tee /proc/sys/vm/drop_caches
足以再次將“緩衝區”降低到 4.5M。這證明我積累的緩衝區是一個“乾淨”的記憶體,Linux 可以在需要時立即刪除。該系統不會累積未寫入的數據。(drop_caches
不執行任何寫回,因此不能刪除臟頁。如果您想執行一個首先清理記憶體的測試,您將使用該sync
命令)。整個mysql目錄只有150M。累積的緩衝區必須代表來自 mysql 寫入的元數據塊,但令我驚訝的是,這些數據會有如此多的元數據塊。