30%的RAM是“缓冲区”。它是什么?


13
$ 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

如何在输出中描述或解释“缓冲区” free

我对该系统没有任何(已知)问题。我只是感到惊讶和奇怪,看到“缓冲区”几乎与“缓存”一样高(155M与180M)。我认为“缓存”代表文件内容的页面缓存,并且往往是“缓存/缓冲区”的最重要部分。我不太清楚什么是“缓冲区”。

例如,我将其与具有更多RAM的笔记本电脑进行了比较。在我的笔记本电脑上,“缓冲区”数字比“缓存”(200M与4G)小一个数量级。如果我对什么是“缓冲区”有一个正确的了解,那么我可以开始问为什么在较小的系统上缓冲区可能会增长到如此大的比例。

man proc (我忽略了“大”的荒谬定义):

缓冲液%lu

相对临时存储的原始磁盘块不应太大(20MB左右)。

缓存%lu

从磁盘读取的文件的内存中缓存(页面缓存)。不包括SwapCached。


$ free -V
free from procps-ng 3.3.12
$ uname -r
4.9.0-6-marvell
$ systemd-detect-virt
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           

3

Answers:


14
  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)。我们不必太担心细节,但是这段历史将是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层来处理其物理块日志记录,并且该层从根本上使用缓冲区高速缓存。

- 电子邮件文章特德左宗棠,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中缺少某些内容。

4.我们为什么Buffers特别期望会更大或更小?

在这种情况下,原来的ext4的日志大小为我的文件系统为128M。因此,这说明了为什么:1)我的缓冲区高速缓存可以稳定在稍微超过128M的水平;2)缓冲区缓存与笔记本电脑上的RAM数量不成比例。

对于其他一些可能的原因,请参见free输出中的buffers列是什么? 注意,报告的“缓冲区” 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的电子邮件,并且对它强调缓存很感兴趣。如果“脏”的写入数据能够达到系统上RAM的30%,我会感到惊讶。 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写入的元数据块,但令我惊讶的是,该数据将有那么多的元数据块。


3

您的版本free具有正确的想法。默认情况下,它在报表中合并了缓冲区和缓存。这是因为它们基本上是同一件事。它们都是计算机在RAM(快速二级存储:磁盘和SSD)中的记忆,这是读取磁盘和SSD时已经看到的。

如果操作系统认为该内存可以更好地用于其他用途,则可以释放该内存。因此,不必担心缓冲区和缓存。

但是,观看DVD会导致缓冲区上升,并逐出其他缓冲区/缓存内容。因此,您可以使用nocache运行DVD播放器(如果引起问题)。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.