国产精品电影_久久视频免费_欧美日韩国产激情_成年人视频免费在线播放_日本久久亚洲电影_久久都是精品_66av99_九色精品美女在线_蜜臀a∨国产成人精品_冲田杏梨av在线_欧美精品在线一区二区三区_麻豆mv在线看

一文看懂什么是頁緩存(Page Cache)

商務辦公
我們知道文件一般存放在硬盤(機械硬盤或固態(tài)硬盤)中,CPU 并不能直接訪問硬盤中的數(shù)據(jù),而是需要先將硬盤中的數(shù)據(jù)讀入到內(nèi)存中,然后才能被 CPU 訪問。

[[409491]]

本文轉(zhuǎn)載自微信公眾號「Linux內(nèi)核那些事」,作者songsong001 。轉(zhuǎn)載本文請聯(lián)系Linux內(nèi)核那些事公眾號。

我們知道文件一般存放在硬盤(機械硬盤或固態(tài)硬盤)中,CPU 并不能直接訪問硬盤中的數(shù)據(jù),而是需要先將硬盤中的數(shù)據(jù)讀入到內(nèi)存中,然后才能被 CPU 訪問。

由于讀寫硬盤的速度比讀寫內(nèi)存要慢很多(DDR4 內(nèi)存讀寫速度是機械硬盤500倍,是固態(tài)硬盤的200倍),所以為了避免每次讀寫文件時,都需要對硬盤進行讀寫操作,Linux 內(nèi)核使用 頁緩存(Page Cache) 機制來對文件中的數(shù)據(jù)進行緩存。

本文使用的 Linux 內(nèi)核版本為:Linux-2.6.23

什么是頁緩存

為了提升對文件的讀寫效率,Linux 內(nèi)核會以頁大小(4KB)為單位,將文件劃分為多數(shù)據(jù)塊。當用戶對文件中的某個數(shù)據(jù)塊進行讀寫操作時,內(nèi)核首先會申請一個內(nèi)存頁(稱為 頁緩存)與文件中的數(shù)據(jù)塊進行綁定。如下圖所示:

如上圖所示,當用戶對文件進行讀寫時,實際上是對文件的 頁緩存 進行讀寫。所以對文件進行讀寫操作時,會分以下兩種情況進行處理:

  • 當從文件中讀取數(shù)據(jù)時,如果要讀取的數(shù)據(jù)所在的頁緩存已經(jīng)存在,那么就直接把頁緩存的數(shù)據(jù)拷貝給用戶即可。否則,內(nèi)核首先會申請一個空閑的內(nèi)存頁(頁緩存),然后從文件中讀取數(shù)據(jù)到頁緩存,并且把頁緩存的數(shù)據(jù)拷貝給用戶。
  • 當向文件中寫入數(shù)據(jù)時,如果要寫入的數(shù)據(jù)所在的頁緩存已經(jīng)存在,那么直接把新數(shù)據(jù)寫入到頁緩存即可。否則,內(nèi)核首先會申請一個空閑的內(nèi)存頁(頁緩存),然后從文件中讀取數(shù)據(jù)到頁緩存,并且把新數(shù)據(jù)寫入到頁緩存中。對于被修改的頁緩存,內(nèi)核會定時把這些頁緩存刷新到文件中。

頁緩存的實現(xiàn)

前面主要介紹了頁緩存的作用和原理,接下來我們將會分析 Linux 內(nèi)核是怎么實現(xiàn)頁緩存機制的。

1. address_space

在 Linux 內(nèi)核中,使用 file 對象來描述一個被打開的文件,其中有個名為 f_mapping 的字段,定義如下:

  1. struct file { 
  2.     ... 
  3.     struct address_space *f_mapping; 
  4. }; 

從上面代碼可以看出,f_mapping 字段的類型為 address_space 結(jié)構(gòu),其定義如下:

  1. struct address_space { 
  2.     struct inode           *host;      /* owner: inode, block_device */ 
  3.     struct radix_tree_root page_tree;  /* radix tree of all pages */ 
  4.     rwlock_t               tree_lock;  /* and rwlock protecting it */ 
  5.     ... 
  6. }; 

address_space 結(jié)構(gòu)其中的一個作用就是用于存儲文件的 頁緩存,下面介紹一下各個字段的作用:

  • host:指向當前 address_space 對象所屬的文件 inode 對象(每個文件都使用一個 inode 對象表示)。
  • page_tree:用于存儲當前文件的 頁緩存。
  • tree_lock:用于防止并發(fā)訪問 page_tree 導致的資源競爭問題。

從 address_space 對象的定義可以看出,文件的 頁緩存 使用了 radix樹 來存儲。

radix樹:又名基數(shù)樹,它使用鍵值(key-value)對的形式來保存數(shù)據(jù),并且可以通過鍵快速查找到其對應的值。內(nèi)核以文件讀寫操作中的數(shù)據(jù) 偏移量 作為鍵,以數(shù)據(jù)偏移量所在的 頁緩存 作為值,存儲在 address_space 結(jié)構(gòu)的 page_tree 字段中。

下圖展示了上述各個結(jié)構(gòu)之間的關(guān)系:

如果對 radix樹 不太了解,可以簡單將其看成可以通過文件偏移量快速找到其所在 頁緩存 的結(jié)構(gòu),有機會我會另外寫一篇關(guān)于 radix樹 的文章。

2. 讀文件操作

現(xiàn)在我們來分析一下讀取文件數(shù)據(jù)的過程,用戶可以通過調(diào)用 read 系統(tǒng)調(diào)用來讀取文件中的數(shù)據(jù),其調(diào)用鏈如下:

  1. read() 
  2. └→ sys_read() 
  3.    └→ vfs_read() 
  4.       └→ do_sync_read() 
  5.          └→ generic_file_aio_read() 
  6.             └→ do_generic_file_read() 
  7.                └→ do_generic_mapping_read() 

從上面的調(diào)用鏈可以看出,read 系統(tǒng)調(diào)用最終會調(diào)用 do_generic_mapping_read 函數(shù)來讀取文件中的數(shù)據(jù),其實現(xiàn)如下:

  1. void 
  2. do_generic_mapping_read(struct address_space *mapping, 
  3.                         struct file_ra_state *_ra, 
  4.                         struct file *filp, 
  5.                         loff_t *ppos, 
  6.                         read_descriptor_t *desc
  7.                         read_actor_t actor) 
  8.     struct inode *inode = mapping->host; 
  9.     unsigned long index
  10.     struct page *cached_page; 
  11.     ... 
  12.  
  13.     cached_page = NULL
  14.     index = *ppos >> PAGE_CACHE_SHIFT; 
  15.     ... 
  16.  
  17.     for (;;) { 
  18.         struct page *page; 
  19.         ... 
  20.  
  21. find_page: 
  22.         // 1. 查找文件偏移量所在的頁緩存是否存在 
  23.         page = find_get_page(mapping, index); 
  24.         if (!page) { 
  25.             ... 
  26.             // 2. 如果頁緩存不存在, 那么跳到 no_cached_page 進行處理 
  27.             goto no_cached_page;  
  28.         } 
  29.         ... 
  30.  
  31. page_ok: 
  32.         ... 
  33.         // 3. 如果頁緩存存在, 那么把頁緩存的數(shù)據(jù)拷貝到用戶應用程序的內(nèi)存中 
  34.         ret = actor(desc, page, offset, nr); 
  35.         ... 
  36.         if (ret == nr && desc->count
  37.             continue
  38.         goto out
  39.         ... 
  40.  
  41. readpage: 
  42.         // 4. 從文件讀取數(shù)據(jù)到頁緩存中 
  43.         error = mapping->a_ops->readpage(filp, page); 
  44.         ... 
  45.         goto page_ok; 
  46.         ... 
  47.  
  48. no_cached_page: 
  49.         if (!cached_page) { 
  50.             // 5. 申請一個內(nèi)存頁作為頁緩存 
  51.             cached_page = page_cache_alloc_cold(mapping); 
  52.             ... 
  53.         } 
  54.  
  55.         // 6. 把新申請的頁緩存添加到文件頁緩存中 
  56.         error = add_to_page_cache_lru(cached_page, mapping, index, GFP_KERNEL); 
  57.         ... 
  58.         page = cached_page; 
  59.         cached_page = NULL
  60.         goto readpage; 
  61.     } 
  62.  
  63. out
  64.     ... 

do_generic_mapping_read 函數(shù)的實現(xiàn)比較復雜,經(jīng)過精簡后,上面代碼只留下最重要的邏輯,可以歸納為以下幾個步驟:

  • 通過調(diào)用 find_get_page 函數(shù)查找要讀取的文件偏移量所對應的頁緩存是否存在,如果存在就把頁緩存中的數(shù)據(jù)拷貝到應用程序的內(nèi)存中。
  • 否則調(diào)用 page_cache_alloc_cold 函數(shù)申請一個空閑的內(nèi)存頁作為新的頁緩存,并且通過調(diào)用 add_to_page_cache_lru 函數(shù)把新申請的頁緩存添加到文件頁緩存和 LRU 隊列中(后面會介紹)。
  • 通過調(diào)用 readpage 接口從文件中讀取數(shù)據(jù)到頁緩存中,并且把頁緩存的數(shù)據(jù)拷貝到應用程序的內(nèi)存中。

從上面代碼可以看出,當頁緩存不存在時會申請一塊空閑的內(nèi)存頁作為頁緩存,并且通過調(diào)用 add_to_page_cache_lru 函數(shù)把其添加到文件的頁緩存和 LRU 隊列中。我們來看看 add_to_page_cache_lru 函數(shù)的實現(xiàn):

  1.  int add_to_page_cache_lru(struct page *page, struct address_space *mapping, 
  2.                            pgoff_t offset, gfp_t gfp_mask) 
  3.     // 1. 把頁緩存添加到文件頁緩存中 
  4.     int ret = add_to_page_cache(page, mapping, offset, gfp_mask); 
  5.     if (ret == 0) 
  6.         lru_cache_add(page); // 2. 把頁緩存添加到 LRU 隊列中 
  7.     return ret; 

add_to_page_cache_lru 函數(shù)主要完成兩個工作:

  • 通過調(diào)用 add_to_page_cache 函數(shù)把頁緩存添加到文件頁緩存中,也就是添加到 address_space 結(jié)構(gòu)的 page_tree 字段中。
  • 通過調(diào)用 lru_cache_add 函數(shù)把頁緩存添加到 LRU 隊列中。LRU 隊列用于當系統(tǒng)內(nèi)存不足時,對頁緩存進行清理時使用。

總結(jié) 

本文主要介紹了 頁緩存 的作用和原理,并且介紹了在讀取文件數(shù)據(jù)時對頁緩存的處理過程。本文并沒有介紹寫文件操作對應的頁緩存處理和當系統(tǒng)內(nèi)存不足時怎么釋放頁緩存,有興趣的話可以自行閱讀相關(guān)的代碼實現(xiàn)。

 

責任編輯:武曉燕 來源: Linux內(nèi)核那些事
相關(guān)推薦

2021-02-21 11:25:17

云計算IaaSPaaS

2022-03-29 08:02:01

數(shù)字孿生能源程序

2021-02-08 22:23:16

云計算辦公硬件

2021-10-17 19:48:10

擴展頁表虛擬機

2020-03-31 14:40:24

HashMap源碼Java

2025-07-11 01:45:00

SIM卡模塊識別

2016-08-18 00:21:12

網(wǎng)絡爬蟲抓取網(wǎng)絡

2024-08-12 12:30:27

2021-08-02 06:56:19

TypeScript編程語言編譯器

2025-01-20 09:15:00

iOS 18.3蘋果iOS 18

2019-05-22 09:50:42

Python沙箱逃逸網(wǎng)絡攻擊

2019-07-01 09:22:15

Linux操作系統(tǒng)硬件

2021-05-12 15:16:17

JUCAQSJava

2025-03-25 09:06:11

2022-04-26 13:41:16

區(qū)塊鏈比特幣數(shù)據(jù)庫

2021-05-11 10:40:29

JUCAQSJava

2023-04-10 11:35:31

評估模型業(yè)務流程

2024-12-30 07:30:00

PLC通訊協(xié)議

2023-12-18 10:45:31

2019-02-13 15:38:09

存儲虛擬化云計算
點贊
收藏

51CTO技術(shù)棧公眾號

国产美女精品久久久| 久久久国产精华| 亚洲大胆人体av| 亚洲高清免费在线观看| 久久婷婷激情| 成人免费网站在线看| 婷婷六月国产精品久久不卡| 中文字幕的久久| 看一级黄色录像| 天使萌一区二区三区免费观看| 97香蕉超级碰碰久久免费软件| 日本免费久久| 日韩精品在线观看网站| 婷婷视频在线| 日韩欧美中文字幕在线播放| 欧美黑人经典片免费观看| 日韩精彩视频在线观看| 国产伦精品一区二区三| 91综合在线| 国产在线视频欧美| 99国产**精品****| 91久久精品一区| 日韩国产专区| 色先锋aa成人| 加勒比一区二区三区| av在线不卡电影| 亚洲高清在线播放| 91影院成人| 国产一区私人高清影院| 在线日韩一区| 成人在线视频福利| 午夜国产精品视频| 91精品国产自产91精品| julia一区二区三区中文字幕| 日韩三级在线免费观看| 中文字幕在线视频观看| 国产精品久久久久久久久免费丝袜 | 国产精品亚洲片在线播放| 久久视频这里只有精品| 一区二区三区日本视频| 精品国产欧美一区二区五十路| 国产精品xnxxcom| 国产精品夫妻激情| 日本欧美加勒比视频| 日本婷婷久久久久久久久一区二区| 夜夜精品视频| 欧美精品一区二区三区在线四季| 欧美成人自拍| 日韩一区二区精品葵司在线 | 麻豆成人久久精品二区三区小说| 国产精品一国产精品最新章节| 亚洲天堂男人| 丰满女人性猛交| 成人av网址在线| 97福利电影| 91精品国产一区二区三区蜜臀| 成人看片网页| 国产女人18毛片水18精品| 亚洲小说欧美另类婷婷| 视频一区二区三| 91亚洲午夜精品久久久久久| 午夜影院在线免费观看| 亚洲韩国青草视频| 日韩在线观看| 欧美特级限制片免费在线观看| 亚洲成人一区二区在线观看| 四虎精品成人免费网站| 欧美一区二区三区四区在线观看| 国产麻豆一区二区三区| 不卡日韩av| 中文字幕一区二区三中文字幕| 麻豆视频在线观看免费网站| 九九视频这里只有精品| 日韩vs国产vs欧美| 成人性视频欧美一区二区三区| 香蕉成人伊视频在线观看| 91精品国产色综合久久不卡粉嫩| 国产精品乱码一区二区三区| 99视频免费| 亚洲精品wwww| 久久成人福利视频| 国产欧美日韩不卡| 羞羞视频在线观看免费| 国产999视频| 久久久久久9999| 欧美黑人xx片| 久久国产日韩欧美| 日韩欧美中文第一页| 国产不卡精品| 日韩视频第二页| 在线观看精品国产视频| 免费高清在线一区| 91porn在线观看| 99久久综合狠狠综合久久止| 99久久99久久精品免费观看| 五月婷婷视频在线观看| 亚洲欧美日韩人成在线播放| 美女福利精品视频| 久久亚洲国产精品一区二区| av在线1区2区| 伊人久久大香线蕉午夜av| 欧美美女网站色| 99国产精品久久久久久久| 全网国产福利在线播放| 国产有码在线一区二区视频| 精品成人av一区| 国产综合自拍| xxxcom在线观看| 中文字幕乱码一区二区三区| 亚洲电影免费观看高清完整版在线 | 岛国av免费在线观看| 91麻豆精品国产91久久久久| 先锋影音一区二区| 中文字幕国产在线| 日韩精品在线视频免费观看| 精品国产一区二区三区久久狼5月 精品国产一区二区三区久久久狼 精品国产一区二区三区久久久 | 91精品综合久久久久久| 日本不卡视频在线| 国产精品极品国产中出| 婷婷av在线| 加勒比日本影视| 亚洲精品高清国产一线久久| 日韩一级欧美一级| av在线不卡免费看| 男同互操gay射视频在线看| 波多野洁衣一区| 在线观看你懂得| 亚洲亚洲精品三区日韩精品在线视频| 亚洲视频国产视频| 色欧美片视频在线观看在线视频| 日韩二区三区四区| 亚洲免费婷婷| 日本成熟性欧美| 在线观看91精品国产麻豆| 亚洲综合区在线| 成人xvideos免费视频| 欧美va亚洲va香蕉在线| 日本亚洲最大的色成网站www| 欧美日韩123区| 国产国语**毛片高清视频| 亚洲蜜桃在线| 国产精品久久久久av| 伦理中文字幕亚洲| 亚洲福利视频久久| 欧美一区欧美二区| 日本韩国欧美国产| 亚洲已满18点击进入久久| 国产精品日韩精品欧美精品| av一区二区在线观看| 精品国产18久久久久久二百| caoporn视频在线| 在线黄色国产视频| 精品视频一区二区在线| 日本成人看片网址| 精品综合在线| 激情欧美一区二区三区中文字幕| 国产精品欧美一区二区| 国产+人+亚洲| 爱福利视频一区| 欧美在线激情网| 欧美岛国在线观看| 91麻豆精品| 精品精品导航| 国产精品xnxxcom| 精品久久ai| 国产亚洲网站| 中文字幕免费观看一区| 午夜精品福利一区二区三区蜜桃| 欧美一级电影网站| 热久久免费视频精品| 久久久久久欧美精品色一二三四 | 欧美一区二区三区日韩视频| 欧美mv日韩mv亚洲| 天天av天天翘天天综合网色鬼国产 | 久久在精品线影院精品国产| 国产一区在线免费| 黄色av网站在线免费观看| 亚州综合一区| 中文字幕在线一区二区三区| 亚洲一区二区久久久| 黄色一级片网址| 激情开心成人网| 91原创在线视频| 九九热99久久久国产盗摄| 欧美亚洲国产成人| 91综合久久爱com| 成人av网站免费| 国产一区二区日韩精品欧美精品| 欧洲亚洲一区二区三区四区五区| 在线看av的网址| 激情成人综合| 精品福利视频一区二区三区| 男女啪啪免费观看| 99精品国产一区二区三区2021| av在线播放成人| 欧美成人全部免费| 在线播放evaelfie极品| 精品久久成人| 亚洲精品88| 欧美日韩国产综合视频|