tft每日頭條

 > 生活

 > linux查看cachebuffer中的文件

linux查看cachebuffer中的文件

生活 更新时间:2024-08-03 14:16:49

free 命令是Linux系統上查看内存使用狀況最常用的工具,然而很少有人能說清楚 “buffers” 與 “cached” 之間的區别:

linux查看cachebuffer中的文件(幹貨linuxfree)1

我們先抛出結論,如果你對研究過程感興趣可以繼續閱讀後面的段落:

“buffers” 表示塊設備(block device)所占用的緩存頁,包括:直接讀寫塊設備、以及文件系統元數據(metadata)比如SuperBlock所使用的緩存頁;“cached” 表示普通文件數據所占用的緩存頁。

下面是分析過程:

先用 strace 跟蹤 free 命令,看看它是如何計算 “buffers” 和 “cached” 的:

# strace free ... open("/proc/meminfo", O_RDONLY) = 3 lseek(3, 0, SEEK_SET) = 0 read(3, "MemTotal: 3848656 kB\nMemF"..., 2047) = 1170 ...

顯然 free 命令是從 /proc/meminfo 中讀取信息的,跟我們直接讀到的結果一樣:

# cat /proc/meminfo MemTotal: 3848656 kB MemFree: 865640 kB Buffers: 324432 kB Cached: 2024904 kB ... SwapTotal: 2031612 kB SwapFree: 2031612 kB ... Shmem: 5312 kB ...

那麼 /proc/meminfo 中的 “Buffers” 和 “Cached” 又是如何得來的呢?這回沒法偷懶,隻能去看源代碼了。源代碼文件是:fs/proc/meminfo.c ,我們感興趣的函數是:meminfo_proc_show(),閱讀得知:

“Cached” 來自于以下公式:global_page_state(NR_FILE_PAGES) – total_swapcache_pages – i.bufferram

global_page_state(NR_FILE_PAGES) 表示所有的緩存頁(page cache)的總和,它包括:

  • “Cached”
  • “Buffers” 也就是上面公式中的 i.bufferram,來自于 nr_blockdev_pages() 函數的返回值。
  • 交換區緩存(swap cache)

global_page_state(NR_FILE_PAGES) 來自 vmstat[NR_FILE_PAGES],vmstat[NR_FILE_PAGES] 可以通過 /proc/vmstat 來查看,表示所有緩存頁的總數量:

# cat /proc/vmstat ... nr_file_pages 587334 ...

注意以上nr_file_pages是以page為單位(一個page等于4KB),而free命令是以KB為單位的。

直接修改 nr_file_pages 的内核函數是:__inc_zone_page_state(page, NR_FILE_PAGES) 和__dec_zone_page_state(page, NR_FILE_PAGES),一個用于增加,一個用于減少。

Swap Cache是什麼?

用戶進程的内存頁分為兩種:file-backed pages(與文件對應的内存頁)和anonymous pages(匿名頁)。匿名頁(anonymous pages)是沒有關聯任何文件的,比如用戶進程通過malloc()申請的内存頁,如果發生swapping換頁,它們沒有關聯的文件進行回寫,所以隻能寫入到交換區裡。

交換區可以包括一個或多個交換區設備(裸盤、邏輯卷、文件都可以充當交換區設備),每一個交換區設備在内存裡都有對應的swap cache,可以把swap cache理解為交換區設備的”page cache”:page cache對應的是一個個文件,swap cache對應的是一個個交換區設備,kernel管理swap cache與管理page cache一樣,用的都是radix-tree,唯一的區别是:page cache與文件的對應關系在打開文件時就确定了,而一個匿名頁隻有在即将被swap-out的時候才決定它會被放到哪一個交換區設備,即匿名頁與swap cache的對應關系在即将被swap-out時才确立。

并不是每一個匿名頁都在swap cache中,隻有以下情形之一的匿名頁才在:

  • 匿名頁即将被swap-out時會先被放進swap cache,但通常隻存在很短暫的時間,因為緊接着在pageout完成之後它就會從swap cache中删除,畢竟swap-out的目的就是為了騰出空閑内存;【注:參見mm/vmscan.c: shrink_page_list(),它調用的add_to_swap()會把swap cache頁面标記成dirty,然後它調用try_to_unmap()将頁面對應的page table mapping都删除,再調用pageout()回寫dirty page,最後try_to_free_swap()會把該頁從swap cache中删除。】
  • 曾經被swap-out現在又被swap-in的匿名頁會在swap cache中,直到頁面中的内容發生變化、或者原來用過的交換區空間被回收為止。【注:當匿名頁的内容發生變化時會删除對應的swap cache,代碼參見mm/swapfile.c: reuse_swap_page()。】
“cached”:

“Cached” 表示除去 “buffers” 和 “swap cache” 之外,剩下的也就是普通文件的緩存頁的數量:global_page_state(NR_FILE_PAGES) – total_swapcache_pages – i.bufferram所以關鍵還是要理解 “buffers” 是什麼含義。

“buffers” :

從源代碼中看到,”buffers” 來自于 nr_blockdev_pages() 函數的返回值:

long nr_blockdev_pages(void) { struct block_device *bdev; long ret = 0; spin_lock(&bdev_lock); list_for_each_entry(bdev, &all_bdevs, bd_list) { ret = bdev->bd_inode->i_mapping->nrpages; } spin_unlock(&bdev_lock); return ret; }

這段代碼的意思是遍曆所有的塊設備(block device),累加每個塊設備的inode的i_mapping的頁數,統計得到的就是 buffers。顯然 buffers 是與塊設備直接相關的。

那麼誰會更新塊設備的緩存頁數量(nrpages)呢?我們繼續向下看。

搜索kernel源代碼發現,最終更新mapping->nrpages字段的函數就是:pagemap.h: add_to_page_cache> filemap.c: add_to_page_cache_locked> __add_to_page_cache_locked> page_cache_tree_insert和:filemap.c: delete_from_page_cache> __delete_from_page_cache> page_cache_tree_delete

static inline int add_to_page_cache(struct page *page, struct address_space *mapping, pgoff_t offset, gfp_t gfp_mask) { int error; __set_page_locked(page); error = add_to_page_cache_locked(page, mapping, offset, gfp_mask); if (unlikely(error)) __clear_page_locked(page); return error; } void delete_from_page_cache(struct page *page) { struct address_space *mapping = page->mapping; void (*freepage)(struct page *); BUG_ON(!PageLocked(page)); freepage = mapping->a_ops->freepage; spin_lock_irq(&mapping->tree_lock); __delete_from_page_cache(page, NULL); spin_unlock_irq(&mapping->tree_lock); mem_cgroup_uncharge_cache_page(page); if (freepage) freepage(page); page_cache_release(page); }

這兩個函數是通用的,block device 和 文件inode 都可以調用,至于更新的是塊設備的(buffers)還是文件的(cached),取決于參數變量mapping:如果mapping對應的是塊設備,那麼相應的統計信息會反映在 “buffers” 中;如果mapping對應的是文件inode,影響的就是 “cached”。我們下面看看kernel中哪些地方會把塊設備的mapping傳遞進來。

首先是塊設備本身,打開時使用 bdev->bd_inode->i_mapping。

static int blkdev_open(struct inode * inode, struct file * filp) { struct block_device *bdev; /* * Preserve backwards compatibility and allow large file access * even if userspace doesn't ask for it explicitly. Some mkfs * binary needs it. We might want to drop this workaround * during an unstable branch. */ filp->f_flags |= O_LARGEFILE; if (filp->f_flags & O_NDELAY) filp->f_mode |= FMODE_NDELAY; if (filp->f_flags & O_EXCL) filp->f_mode |= FMODE_EXCL; if ((filp->f_flags & O_ACCMODE) == 3) filp->f_mode |= FMODE_WRITE_IOCTL; bdev = bd_acquire(inode); if (bdev == NULL) return -ENOMEM; filp->f_mapping = bdev->bd_inode->i_mapping; return blkdev_get(bdev, filp->f_mode, filp); }

其次,文件系統的Superblock也是使用塊設備:

struct super_block { ... struct block_device *s_bdev; ... } int inode_init_always(struct super_block *sb, struct inode *inode) { ... if (sb->s_bdev) { struct backing_dev_info *bdi; bdi = sb->s_bdev->bd_inode->i_mapping->backing_dev_info; mapping->backing_dev_info = bdi; } ... }

sb表示SuperBlock,s_bdev就是塊設備。Superblock是文件系統的metadata(元數據),不屬于文件,沒有對應的inode,所以,對metadata操作所涉及的緩存頁都隻能利用塊設備mapping,算入 buffers 的統計值内。

如果文件含有間接塊(indirect blocks),因為間接塊也屬于metadata,所以走的也是塊設備的mapping。查看源代碼,果然如此:

ext4_get_blocks -> ext4_ind_get_blocks -> ext4_get_branch -> sb_getblk static inline struct buffer_head * sb_getblk(struct super_block *sb, sector_t block) { return __getblk(sb->s_bdev, block, sb->s_blocksize); }

這樣我們就知道了”buffers” 是塊設備(block device)占用的緩存頁,分為兩種情況:

  • 直接對塊設備進行讀寫操作;
  • 文件系統的metadata(元數據),比如 SuperBlock。
驗證:

現在我們來做個測試,驗證一下上述結論。既然文件系統的metadata會用到 “buffers”,我們用 find 命令掃描文件系統,觀察 “buffers” 增加的情況:

# free total used free shared buffers cached Mem: 3848656 2889508 959148 5316 263896 2023340 -/ buffers/cache: 602272 3246384 Swap: 2031612 0 2031612 # find / -name abc.def # free total used free shared buffers cached Mem: 3848656 2984052 864604 5320 319612 2023348 -/ buffers/cache: 641092 3207564 Swap: 2031612 0 2031612

再測試一下直接讀取block device,觀察”buffers”增加的現象:

# free total used free shared buffers cached Mem: 3848656 3006944 841712 5316 331020 2028648 -/ buffers/cache: 647276 3201380 Swap: 2031612 0 2031612 # dd if=/dev/sda1 of=/dev/null count=2000 2000 0 records in 2000 0 records out 1024000 bytes (1.0 MB) copied, 0.026413 s, 38.8 MB/s # free total used free shared buffers cached Mem: 3848656 3007704 840952 5316 331872 2028692 -/ buffers/cache: 647140 3201516 Swap: 2031612 0 2031612

結論:

free 命令所顯示的 “buffers” 表示塊設備(block device)所占用的緩存頁,包括直接讀寫塊設備、以及文件系統元數據(metadata)如SuperBlock所使用的緩存頁;而 “cached” 表示普通文件所占用的緩存頁。

更多linux内核學習請觀看我的《linux内核開發100講》免費視頻教程。

關注我,更多linux内核知識科普。

,

更多精彩资讯请关注tft每日頭條,我们将持续为您更新最新资讯!

查看全部

相关生活资讯推荐

热门生活资讯推荐

网友关注

Copyright 2023-2024 - www.tftnews.com All Rights Reserved