第五章 WebKit之緩存機(jī)制

5.1 WebKit緩存概述

WebKit緩存包含MemoryCache、DiskCache和PageCache三種。

MemoryCache是WebKit最早實(shí)現(xiàn)且相對(duì)成熟的緩存機(jī)制扼鞋。MemoryCache岖赋,顧名思義于宙,就是將資源緩存到內(nèi)存中,等待下次訪(fǎng)問(wèn)時(shí)不需要重新下載資源物延,而直接從內(nèi)存中獲取。這種緩存方式常用在瀏覽網(wǎng)頁(yè)返回上一頁(yè)操作仅父,當(dāng)用戶(hù)瀏覽器跳轉(zhuǎn)另一個(gè)頁(yè)面時(shí)叛薯,會(huì)緩存上一個(gè)頁(yè)面(緩存空間足夠的話(huà)可以緩存更多頁(yè)面資源)的資源,當(dāng)再次返回上一個(gè)頁(yè)面時(shí)笙纤,WebKit對(duì)已經(jīng)緩存的資源不再通過(guò)網(wǎng)絡(luò)渠道下載耗溜,而是直接從內(nèi)存中獲取數(shù)據(jù),大大提高了網(wǎng)頁(yè)加載的效率省容。但存在的局限是只能緩存“派生資源”抖拴。

DiskCache,顧名思義腥椒,就是將資源緩存到磁盤(pán)中阿宅,等待下次訪(fǎng)問(wèn)時(shí)不需要重新下載資源,而直接從磁盤(pán)中獲取寞酿。DiskCache的實(shí)現(xiàn)跟平臺(tái)息息相關(guān)家夺,由于本文使用的第三方網(wǎng)絡(luò)庫(kù)為curl,所以之后講解的代碼也是curl port代碼伐弹,它的直接操作對(duì)象為CurlCacheManager類(lèi)拉馋。DiskCache與MemoryCache最大的區(qū)別在于榨为,當(dāng)退出進(jìn)程時(shí),內(nèi)存中的數(shù)據(jù)會(huì)被清空煌茴,而磁盤(pán)的數(shù)據(jù)不會(huì)随闺,所以,當(dāng)下次再進(jìn)入該進(jìn)程時(shí)蔓腐,該進(jìn)程仍可以從DiskCache中獲得數(shù)據(jù)矩乐,而MemoryCache則不行。WebKit早已經(jīng)存在DiskCache代碼回论,但這個(gè)功能默認(rèn)是關(guān)閉狀態(tài)散罕,官方解釋?zhuān)@段代碼存在不定性的問(wèn)題,請(qǐng)慎用傀蓉!確實(shí)欧漱,本人曾經(jīng)研究過(guò)DiskCache代碼,并使用它葬燎,經(jīng)常會(huì)出現(xiàn)一些莫名其妙的錯(cuò)誤误甚。或許是現(xiàn)在DiskCache本身機(jī)制還存在問(wèn)題谱净,或許是代碼本身邏輯有問(wèn)題窑邦。但不管怎么說(shuō),研究這一塊對(duì)了解WebKit一些緩存機(jī)制還是很有幫助的壕探。

PageCache冈钦,顧名思義,就是將page描述文檔緩存到內(nèi)存中李请,解決了MemoryCache的弊端派继。由于本人對(duì)這方面還未曾研究,所以后續(xù)也不作詳細(xì)講解捻艳,感興趣的朋友可以在網(wǎng)上搜索一些關(guān)于這方面的博客驾窟。

5.2 MemoryCache詳解

由于MemoryCache流程繁多,通過(guò)時(shí)序圖描述太過(guò)復(fù)雜认轨,所以本人決定用文字描述一下整個(gè)緩存步驟绅络。這里我們還是以image為例,大家也可以參考一下在第四章的image加載時(shí)序圖嘁字。

1.解析html頁(yè)面的時(shí)候恩急,解析到img標(biāo)簽,調(diào)用

HTMLImageElement::create創(chuàng)建HTMLImageElement對(duì)象纪蜒,該對(duì)象包含HTMLImageLoader對(duì)象m_imageLoader

2.解析到img的src屬性衷恭,調(diào)用ImageLoader::updateFromElementIgnoringPreviousError

3.調(diào)用ImageLoader::updateFromElement

4.調(diào)用CachedResourceLoader::requestImage

5.調(diào)用CachedResourceLoader::requestResource,根據(jù)緩存的情況policy字段確定是否可以從緩存獲却啃(use)随珠,或者需要revalidate灭袁,或者需要直接從網(wǎng)絡(luò)獲取(load)

6.調(diào)用CachedResourceLoader::loadResource

7.根據(jù)Resource的類(lèi)型調(diào)用createResource創(chuàng)建對(duì)應(yīng)的CachedResource

8.調(diào)用MemoryCache::add在cache中查找是否有對(duì)應(yīng)的cache條目,如果沒(méi)有創(chuàng)建之

9.調(diào)用CachedImage::load

10.調(diào)用CachedResource::load

11.調(diào)用CachedResourceLoader::load

12.調(diào)用CachedResourceRequest::load

13.創(chuàng)建CachedResourceRequest?對(duì)象窗看,它將作為SubresourceLoader的client

14.調(diào)用ResourceLoaderScheduler::scheduleSubresourceLoad

15.調(diào)用SubresourceLoader::create

16.調(diào)用ResourceLoadScheduler::requestTimerFired

17.調(diào)用ResourceLoader::start

18.調(diào)用ResourceHandle::create?發(fā)起請(qǐng)求

19.收到HTTP響應(yīng)頭部茸歧,調(diào)用ResourceLoader::didReceiveResponse

20.調(diào)用SubresourceLoader::didReceiveResponse處理響應(yīng)頭部,特別是同緩存相關(guān)的頭部显沈,比如304的status code软瞎。如果是304則直接向緩存獲取,如果是200則通過(guò)網(wǎng)絡(luò)加載

21.調(diào)用ResourceLoader::didReceiveResponse

22.收到體部數(shù)據(jù)拉讯,調(diào)用ResourceLoader::didReceiveData

23.調(diào)用SubresourceLoader::didReceiveData

24.調(diào)用ResourceLoader::didReceiveData

25.調(diào)用ResourceLoader::addData將數(shù)據(jù)存儲(chǔ)到SharedBuffer里面

26.調(diào)用CachedResourceRequest::didReceiveData

27.數(shù)據(jù)獲取完畢,調(diào)用ResourceLoader::didFinishLoading

28.調(diào)用SubresourceLoader::didFinishLoading

29.調(diào)用CachedResourceRequest::didFinishLoading

30.調(diào)用CachedResource::finish

31.調(diào)用CachedResourceLoader::loadDone

32.調(diào)用CachedImage::data涤浇,創(chuàng)建對(duì)應(yīng)的Image對(duì)象,解碼

很清楚的看到魔慷,MemoryCache涉及到一個(gè)關(guān)鍵的類(lèi)就是“MemoryCache”芙代。在MemoryCache.cpp中可以看到如下代碼:

MemoryCache* memoryCache()

{

? ? ? ? static MemoryCache* staticCache = new MemoryCache;

? ? ? ? ASSERT(WTF::isMainThread());

? ? ? ? return staticCache;

}

你會(huì)發(fā)現(xiàn)MemoryCache是標(biāo)準(zhǔn)的單例模式!如果想了解MemoryCache相關(guān)功能盖彭,研究MemoryCache.cpp已經(jīng)完成足夠。

MemoryCache時(shí)序圖:

將資源添加到MemoryCache


從MemoryCache里獲取資源

MemoryCache為了避免內(nèi)存溢出页滚,除了可以緩存資源以外召边,還提供了一套清理緩存資源的機(jī)制。這部分實(shí)現(xiàn)也在MemoryCache.cpp可以找到裹驰,下面我們通過(guò)文字的形式來(lái)看看這個(gè)流程隧熙。

調(diào)用MemoryCache::prune()清理緩存入口函數(shù)

調(diào)用MemoryCache::pruneDeadResources()首先清理Dead的緩存,這里Dead的緩存代表頁(yè)面已經(jīng)銷(xiāo)毀幻林,但還保留其數(shù)據(jù)的緩存

調(diào)用MemoryCache::deadCapacity()計(jì)算dead緩存容量大小贞盯,返回capacity

計(jì)算targetSize=capacity * cTargetPrunePercentage;將targetSize傳給下面函數(shù)

調(diào)用MemoryCache::pruneDeadResourcesToSize()開(kāi)始清理Dead緩存

調(diào)用MemoryCache::pruneLiveResources()清理Live的緩存,這里的Live緩存指頁(yè)面加載完沪饺,保留的緩存

調(diào)用MemoryCache::liveCapacity()計(jì)算live緩存容量大小躏敢,返回capacity

計(jì)算targetSize=capacity * cTargetPrunePercentage;將targetSize傳給下面函數(shù)

調(diào)用MemoryCache::pruneLiveResourcesToSize()開(kāi)始清理Live緩存

注:在清理Dead或者Live緩存時(shí)整葡,存在一個(gè)關(guān)鍵參數(shù)cTargetPrunePercentage件余,初始值被設(shè)置為0.95,targetSize=capacity * cTargetPrunePercentage遭居,當(dāng)清理的m_deadsize(或m_livesize) <=targetSize啼器,就不在清理;所以其實(shí)清理只清理了要清理capacity的5%俱萍,剩下的95%都未清理端壳。當(dāng)判斷需要再清理時(shí),還是走以上流程枪蘑,只清理5%损谦。

5.3 DiskCache詳解

前面已經(jīng)簡(jiǎn)單介紹過(guò)了DiskCache岖免。DiskCache與MemoryCache相似之處就是也只能存儲(chǔ)一些派生類(lèi)資源文件。它的存儲(chǔ)形式為一個(gè)index.dat文件成翩,記錄存儲(chǔ)數(shù)據(jù)的url觅捆,然后再分別存儲(chǔ)該url的response信息和content內(nèi)容。Response信息最大作用就是用于判斷服務(wù)器上該url的content內(nèi)容是否被修改麻敌。具體詳見(jiàn):

http://baike.baidu.com/link?url=n5nx7f8fGB_-B3OieAvMvJIGeBNvipb9qGQhYO0YwwBLg6oxqv_05Up3JUJk4jZyAd-KiCM1Hmg4nR23B5BhSq

下面我們簡(jiǎn)單講解一下DiskCache的流程:

1.webkit已啟動(dòng)栅炒,就會(huì)創(chuàng)建CurlCacheManager對(duì)象

2.CurlCacheManager構(gòu)造函數(shù)會(huì)調(diào)用CurlCacheManager::setCacheDirectory

3.調(diào)用fileExists判斷文件夾是否存在,如果存在繼續(xù)术羔,否則調(diào)用makeAllDirectories創(chuàng)建文件夾

4.調(diào)用CurlCacheManager::loadIndex()赢赊,如果本地有緩存文件,它就會(huì)從磁盤(pán)讀取出來(lái)级历,并將數(shù)據(jù)保存在m_index這個(gè)變量中释移,該變量類(lèi)型為HashMap>,分別對(duì)應(yīng)url和數(shù)據(jù)內(nèi)容寥殖。

5.調(diào)用headerCallback函數(shù)玩讳,返回code status為304未修改,就會(huì)去調(diào)用CurlCacheManager::getCachedResponse()嚼贡,如果是200熏纯,就會(huì)下載數(shù)據(jù),并將數(shù)據(jù)的url保存在一個(gè)m_LRUEntryList中

6.調(diào)用CurlCacheManager::readCachedData()

7.調(diào)用CurlCacheEntry::readCachedData()

8.調(diào)用CurlCacheEntry::loadFileToBuffer()將文件中的內(nèi)容讀取出來(lái)保存在一個(gè)buffer中

9.調(diào)用ResourceLoader::didReceiveData()將數(shù)據(jù)獲取粤策,此時(shí)數(shù)據(jù)沒(méi)有通過(guò)網(wǎng)絡(luò)下載樟澜,直接從本地獲取

10.Webkit退出時(shí),調(diào)用CurlCacheManager::~CurlCacheManager()

11.調(diào)用CurlCacheManager::saveIndex()叮盘,該函數(shù)會(huì)去將m_LRUEntryList中的url獲取并寫(xiě)入index.dat文件中


上述流程時(shí)序圖

5.4 本章小結(jié)

本文講解了MemoryCache和DiskCache的功能以及一些方法實(shí)現(xiàn)秩贰,幫助大家了解WebKit緩存機(jī)制。這里強(qiáng)調(diào)一下柔吼,WebKit的緩存機(jī)制算法主要是“最近使用算法”毒费。當(dāng)然,本文并未完全剖析WebKit的緩存機(jī)制一些細(xì)節(jié)處理愈魏,感興趣的朋友可以自己研究一番蝗罗!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市蝌戒,隨后出現(xiàn)的幾起案子串塑,更是在濱河造成了極大的恐慌,老刑警劉巖北苟,帶你破解...
    沈念sama閱讀 222,946評(píng)論 6 518
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件桩匪,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡友鼻,警方通過(guò)查閱死者的電腦和手機(jī)傻昙,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,336評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門(mén)闺骚,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人妆档,你說(shuō)我怎么就攤上這事僻爽。” “怎么了贾惦?”我有些...
    開(kāi)封第一講書(shū)人閱讀 169,716評(píng)論 0 364
  • 文/不壞的土叔 我叫張陵胸梆,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我须板,道長(zhǎng)碰镜,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 60,222評(píng)論 1 300
  • 正文 為了忘掉前任习瑰,我火速辦了婚禮绪颖,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘甜奄。我一直安慰自己柠横,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,223評(píng)論 6 398
  • 文/花漫 我一把揭開(kāi)白布课兄。 她就那樣靜靜地躺著牍氛,像睡著了一般。 火紅的嫁衣襯著肌膚如雪第喳。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 52,807評(píng)論 1 314
  • 那天踱稍,我揣著相機(jī)與錄音曲饱,去河邊找鬼。 笑死珠月,一個(gè)胖子當(dāng)著我的面吹牛扩淀,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播啤挎,決...
    沈念sama閱讀 41,235評(píng)論 3 424
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼驻谆,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了庆聘?” 一聲冷哼從身側(cè)響起胜臊,我...
    開(kāi)封第一講書(shū)人閱讀 40,189評(píng)論 0 277
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎伙判,沒(méi)想到半個(gè)月后象对,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,712評(píng)論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡宴抚,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,775評(píng)論 3 343
  • 正文 我和宋清朗相戀三年勒魔,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了甫煞。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,926評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡冠绢,死狀恐怖抚吠,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情弟胀,我是刑警寧澤楷力,帶...
    沈念sama閱讀 36,580評(píng)論 5 351
  • 正文 年R本政府宣布,位于F島的核電站邮利,受9級(jí)特大地震影響弥雹,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜延届,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,259評(píng)論 3 336
  • 文/蒙蒙 一剪勿、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧方庭,春花似錦厕吉、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,750評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至龄减,卻和暖如春项钮,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背希停。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,867評(píng)論 1 274
  • 我被黑心中介騙來(lái)泰國(guó)打工烁巫, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人宠能。 一個(gè)月前我還...
    沈念sama閱讀 49,368評(píng)論 3 379
  • 正文 我出身青樓亚隙,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親违崇。 傳聞我的和親對(duì)象是個(gè)殘疾皇子阿弃,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,930評(píng)論 2 361

推薦閱讀更多精彩內(nèi)容