Linux

30% 的 RAM 是“緩衝區”。它是什麼?

  • August 2, 2020

如何在輸出中描述或解釋“緩衝區” 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           
  1. “緩衝區”和其他類型的記憶體有什麼區別?
  2. 為什麼這種區別如此突出?為什麼有些人在談論記憶體文件內容時會說“緩衝區記憶體”?
  3. Buffers用來做什麼的?
  4. 為什麼我們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 $$ 讓我們不要太擔心細節,但這段歷史將是 LinuxBuffers單獨報告使用情況的原因之一。 $$ 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 層來處理它們的物理塊日誌,而這一層從根本上使用緩衝區記憶體。

Ted Tso的電子郵件文章,2013 年

在 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。

  1. 為什麼我們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 寫入的元數據塊,但令我驚訝的是,這些數據會有如此多的元數據塊。

引用自:https://unix.stackexchange.com/questions/440558