緩存流程圖
Ⅰ 瀏覽器緩存和伺服器緩存
一、瀏覽器緩存
瀏覽器緩存即http緩存;瀏覽器緩存根據是否需要向伺服器重新發起HTTP請求將緩存過程分為兩個部分,分別是 強制緩存 和 協商緩存 。
瀏覽器第一次請求資源的時候伺服器會告訴客戶端是否應該緩存資源,根據響應報文中HTTP頭的緩存標識,決定是否緩存結果,是則將請求結果和緩存標識存入瀏覽器緩存中。如下圖:
1.強制緩存 :瀏覽器會對緩存進行查找,並根據一定的規則確定是否使用緩存。
強制緩存的緩存規則?
HTTP/1.0 Expires 這個欄位是絕對時間,比如2018年6月30日12:30,然後在這個時間點之前的請求都會使用瀏覽器緩存,除非清除了緩存。
這個欄位的缺點就是只會同步客戶端的時間,這就有可能修改客戶端時間導致緩存失效。
HTTP/1.1 cache-Control 這個是1.1的時候替換Expires的,它會有幾種取值:
public :所有內容都將被緩存(客戶端和代理伺服器都可緩存)
private :所有內容只有客戶端可以緩存, Cache-Control的默認取值
no-cache :客戶端緩存內容,但是是否使用緩存則需要經過協商緩存來驗證決定
no-store :所有內容都不會被緩存,即不使用強制緩存,也不使用協商緩存
max-age=xxx (xxx is numeric) :緩存內容將在xxx秒後失效
比如max-age=500,則在500秒內再次請求會直接只用緩存。
優先性:cache-Control > Expires
如果同時存在,cache-Control會覆蓋Expires。
這個欄位的缺點就是:
如果資源更新的速度是秒以下單位,那麼該緩存是不能被使用的,因為它的時間單位最低是秒。
如果文件是通過伺服器動態生成的,那麼該方法的更新時間永遠是生成的時間,盡管文件可能沒有變化,所以起不到緩存的作用。
上圖中瀏覽器緩存中存在該資源的緩存結果,並且沒有失效,就會直接使用緩存的內容。
上圖中瀏覽器緩存中沒有該資源的緩存結果和標識,就會直接向伺服器發起HTTP請求。
2.協商緩存: 瀏覽器的強制緩存失效後(時間過期),瀏覽器攜帶緩存標識請求伺服器,由伺服器決定是否使用緩存。
伺服器決定的規則?
控制協商緩存的欄位有 Last-Modified / If-Modified-Since 和 Etag / If-None-Match。
①Last-Modified 是伺服器返回給瀏覽器的本資源的最後修改時間。
當下次再次請求的時候,瀏覽器會在請求頭中帶 If-Modified-Since ,即上次請求下來的 Last-Modified 的值,
然後伺服器會用這個值和該資源最後修改的時間比較,如果最後修改時間大於這個值,則會重新請求該資源,返回狀態碼200。
如果這個值和最後修改時間相等,則會返回304,告訴瀏覽器繼續使用緩存。
② Etag 是伺服器返回的一個hash值。
當下次再次請求的時候,瀏覽器會在請求頭中帶 If-None-Match ,即上次請求下來的 Etag 值,
然後伺服器會用這個值和該資源在伺服器的 Etag 值比較,如果一致則會返回304,繼續使用緩存;如果不一致,則會重新請求,返回200。
二、伺服器緩存
上面是一個簡單的流程圖:
用戶1訪問A頁面,伺服器解析A頁面返回給用戶1,同時在伺服器內存上做一定映射,把A頁面緩存在硬碟上面
用戶2訪問A頁面,伺服器直接根據內存上的映射找到對應的頁面緩存,直接返回給用戶2,這樣就減少了伺服器對同一頁面的重復解析
伺服器緩存和瀏覽器緩存的區別:
伺服器緩存是把頁面緩存到伺服器上的硬碟里,而瀏覽器緩存是把頁面緩存到用戶自己的電腦里
Nginx伺服器
Nginx是一個高性能的HTTP和反向代理伺服器。具有非常多的優越性:
在連接高並發的情況下,Nginx是Apache伺服器不錯的替代品,Nginx在美國是做虛擬主機生意的老闆們經常選擇的軟體平台之一。
Nginx提供了expires、etag、if-modified-since指令來實現瀏覽器緩存控制。
nginx -s reload#重新載入配置文件
nginx -s reopen#重新打開log文件
nginx -s stop#快速關閉nginx服務
nginx -s quit #優雅的關閉nginx服務,等待工作進程處理完所有的請求
Nginx設置靜態文件的緩存過期時間
location ~.*\.(js|css|html|png|jpg)$ {
expires 3d;
}
expires 3d;//表示緩存3天
expires 3h;//表示緩存3小時
expires max;//表示緩存10年
expires -1;//表示永遠過期。
如果設置為-1在js、css等靜態文件在沒有修改的情況下返回的是http 304,如果修改返回http 200
對於靜態資源會自動添加ETag,可以通過添加etag off指令禁止生成ETag。如果是靜態文件,那麼Last-Modified值為文件的最後修改時間。
在開發調試web的時候,經常會碰到因瀏覽器緩存(cache)而經常要去清空緩存或者強制刷新來測試的煩惱,提供下apache不緩存配置和nginx不緩存配置的設置。在常用的緩存設置裡面有兩種方式,都是使用add_header來設置:分別為Cache-Control和Pragma。
location ~ .*\.(css|js|swf|php|htm|html )$ {
add_header Cache-Control no-store;
add_header Pragma no-cache;
}
nginx gzip壓縮
使用 gzip 壓縮可以降低網站帶寬消耗,同時提升訪問速度。
主要在nginx服務端將頁面進行壓縮,然後在瀏覽器端進行解壓和解析,
目前大多數流行的瀏覽器都遲滯gzip格式的壓縮,所以不用擔心。
默認情況下,Nginx的gzip壓縮是關閉的,同時,Nginx默認只對text/html進行壓縮
gzip on;
ersio #開啟gzip壓縮輸出
gzip_http_vn 1.0 ;#默認1.1
#其中的gzip_http_version的設置,它的默認值是1.1,就是說對HTTP/1.1協議的請求才會進行gzip壓縮
#如果我們使用了proxy_pass進行反向代理,那麼nginx和後端的upstream server之間是用HTTP/1.0協議通信的。
gzip_vary on ;
#和http頭有關系,加個vary頭,給代理伺服器用的,有的瀏覽器支持壓縮,有的不支持,
#所以避免浪費不支持的也壓縮,所以根據客戶端的HTTP頭來判斷,是否需要壓縮
gzip_comp_level 6;
#設置gzip壓縮等級,等級越底壓縮速度越快文件壓縮比越小,反之速度越慢文件壓縮比越大 1-9
gzip_proxied any;
#Ngnix作為反向代理的時候啟用
#expample:gzip_proxied no-cache;
# off – 關閉所有的代理結果數據壓縮
# expired – 啟用壓縮,如果header中包含」Expires」頭信息
# no-cache – 啟用壓縮,如果header中包含」Cache-Control:no-cache」頭信息
# no-store – 啟用壓縮,如果header中包含」Cache-Control:no-store」頭信息
# private – 啟用壓縮,如果header中包含」Cache-Control:private」頭信息
# no_last_modified – 啟用壓縮,如果header中包含」Last_Modified」頭信息
# no_etag – 啟用壓縮,如果header中包含「ETag」頭信息
# auth – 啟用壓縮,如果header中包含「Authorization」頭信息
# any – 無條件壓縮所有結果數據
gzip_types text/html ;#壓縮的文件類型
#設置需要壓縮的MIME類型,非設置值不進行壓縮
#param:text/html|application/x-javascript|text/css|application/xml
gzip_buffers 16 8k; #設置gzip申請內存的大小,其作用是按塊大小的倍數申請內存空間設置gzip申請內存的大小,其作用是按塊大小的倍數申請內存空間
#設置gzip申請內存的大小,其作用是按塊大小的倍數申請內存空間
# param1:int 增加的倍數
# param2:int(k) 後面單位是k
# example: gzip_buffers 4 8k;
# Disable gzip for certain browsers.
gzip_disable 「MSIE [1-6].(?!.*SV1)」; #ie6不支持gzip,需要禁用掉ie6
Ⅱ 鍥劇墖嫻佺▼鍥炬ā鏉-嫻佺▼鍥懼備綍鍒朵綔錛
鍒嗕韓涓浜涘ソ鐪嬬殑嫻佺▼鍥炬ā鏉榪欐槸鎴戜粠榪呮嵎鐢誨浘緗戠珯涓涓嬭澆鐨勫嚑嬈懼ソ鐪嬬殑嫻佺▼鍥炬ā鏉,鍒嗕韓緇欎綘甯屾湜鍙浠ュ逛綘鏈夋墍甯鍔,涓嬮潰鏄灞曠ず鐨勬ā鏉垮悕縐,妯℃澘綆浠嬩互鍙婁竴寮犳ā鏉跨緝鐣ュ浘銆
1.緇撶畻嫻佺▼鍥
榪欐槸涓涓瀹屾暣鐨勭粨綆楁祦紼嬪浘,閫氳繃浣跨敤涓嶅悓鐨勬祦紼嬪浘鍥懼艦奼囨昏屾垚,灝嗘瘡涓姝ラや腑鏈夊彲鑳藉嚭鐜扮殑涓ょ嶅彲鑳介兘榪涜屼簡鎬葷粨褰掔撼,甯屾湜璇ョ粨綆楁祦紼嬪浘鍙浠ョ粰澶у跺甫鏉ュ府鍔.
2.紿佸彂浜嬩歡澶勭悊嫻佺▼鍥
榪欐槸涓涓紿佸彂浜嬩歡澶勭悊嫻佺▼鍥,瀵圭獊鐒跺彂鐢熺殑浜嬫儏棣栧厛瑕佹壘鍒板師鍥犱箣鍚庤繘琛岃В鍐沖圭獊鍙戜簨浠惰繘琛屽畬緹庣殑澶勭悊.璇ユ祦紼嬪浘妯℃澘涓哄ぇ瀹舵葷粨鐨勫緢璇︾粏,甯屾湜鍙浠ュ甫鏉ュ府鍔.
3.榪涜揣嫻佺▼鍥
璇ユ祦紼嬪浘妯℃澘鎵璁茶堪鐨勪富瑕佸唴瀹逛負榪涜揣,鏍規嵁榪涜揣嫻佺▼浠ュ強榪涜揣涓闇瑕佹敞鎰忕偣緇勫悎鑰屾垚,甯屾湜鍙浠ョ粰澶у跺甫鏉ュ府鍔┿
4.鐢熶駭嫻佺▼鍥
璇ユ祦紼嬪浘閫氳繃5涓姝ラゅ圭敓浜х幆鑺備綔鍑轟簡鎬葷粨,鍒嗗埆鏄紜瀹氱敓浜ц″垝,欏圭洰緇忕悊鎵瑰噯,緇勭粐鐢熶駭,璐ㄦ/宸ユ湡媯楠屼互鍙婅祫鏂欏囨堣繖5涓姝ラ,閫氳繃涓浜涚畝鍗曠殑嫻佺▼鍥懼浘褰㈢粍鍚堝湪涓涓鑰屾垚銆
5.緗戦〉璁捐℃祦紼嬪浘
璇ユ祦紼嬪浘涓昏佸唴瀹瑰洿緇曠綉欏佃捐″睍寮,娓呮櫚鐨勫睍紺烘暣涓榪囩▼鐨勭粯鍒舵祦紼,閫氳繃榪欐牱涓涓鍥懼艦灞曠ず璁╂暣涓璁捐¤繃紼嬫洿鍔犳竻鏅版槑浜.甯屾湜璇ユ祦紼嬪浘妯℃澘鍙浠ュ府鍔╁埌澶у.
6.webkit緙撳瓨嫻佺▼鍥
WebKit鏈鏃╁疄鐜頒笖鐩稿規垚鐔熺殑緙撳瓨鏈哄埗,灝嗚祫婧愮紦瀛樺埌鍐呭瓨涓,絳夊緟涓嬫¤塊棶鏄涓嶉渶瑕侀噸鏂頒笅杞借祫婧,鑰岀洿鎺ヤ粠鍐呭瓨涓鑾峰彇.璇webkit緙撳瓨嫻佺▼鍥炬葷粨浜嗙紦瀛樿繃紼,甯屾湜璇ユ祦紼嬪浘鍙浠ョ粰澶у跺甫鏉ュ府鍔.
嫻佺▼鍥懼備綍鍒朵綔錛浠ュ湪璁懼囪仈鎯沖鉤鏉垮皬鏂般佸瀷鍙稰ADPRO11.5鑻卞哥數鑴戙佹搷浣滅郴緇焀IN10涓撲笟鐗堜互鍙妚isio2010鐗堟湰涓婃搷浣滀負渚,鍙浠ラ氳繃鎵撳紑璇ヨ蔣浠惰繘鍏ャ傜劧鍚庢柊寤洪〉闈,閫夋嫨嫻佺▼鍥捐繘鍏ャ傚湪璇ラ〉闈㈤夋嫨闇瑕佺殑鍚勭嶅艦鐘朵互鍙婅繛鎺ョ嚎鍗沖彲瀹屾垚銆
鍏蜂綋鐨勬搷浣滄柟娉曞備笅:
1銆佸湪鐢佃剳涓婃壘鍒拌ヨ蔣浠,鐐瑰嚮鎵撳紑銆
2銆佽繘鍏ュ埌璇ヨ蔣浠朵互鍚庣偣鍑葷┖鐧界粯鍥炬寜閽銆
3銆佸湪鍑虹幇鐨勯夐」涓鐐瑰嚮鍒涘緩銆
4銆佹ゆ椂鍦ㄥ嚭鐜扮殑欏甸潰涓鐐瑰嚮鏇村氬艦鐘,閫夋嫨嫻佺▼鍥句互鍙婂熀鏈嫻佺▼鍥懼艦鐘躲
5銆侀〉闈㈣煩杞浠ュ悗鍙浠ョ湅鍒板乏渚х殑澶氫釜褰㈢姸,浣跨敤榧犳爣灝嗗叾閫変腑闇瑕佺殑褰㈢姸鍐嶇┖鐧介〉闈涓鐐瑰嚮銆
6銆佺劧鍚庣偣鍑諱笂鏂圭殑榪炴帴綰,灝嗘祦紼嬪浘浜堜互榪炴帴銆
7銆佺戶緇鐐瑰嚮涓婃柟鐨勬枃鏈妗,鐒跺悗鍦ㄦ祦紼嬪浘鐨勫艦鐘朵腑鐐瑰嚮騫惰緭鍏ラ渶瑕佺殑鏂囧瓧鍗沖彲瀹屾垚璇ユ祦紼嬪浘鍒朵綔銆
Ⅲ 聊一聊緩存 [from memory cache 和 from disk cache]
現在簡單的來分析一下,首先,大家可以想一下,瀏覽器的緩存存放在哪裡,如何在瀏覽器中判斷強制緩存是否生效?
先看一下這張圖
會發現在瀏覽器開發者工具的Network的Size欄會出現的三種情況:
狀態碼及區別:
from memory cache(內存中的緩存): 不訪問伺服器,一般已經載入過該資源且緩存在了內存當中,直接從內存中讀取緩存。瀏覽器關閉後,數據將不存在(資源被釋放掉了),再次打開相同的頁面時,不會出現from memory cache。
from disk cache(是硬碟中的緩存): 不訪問伺服器,已經在之前的某個時間載入過該資源,直接從硬碟中讀取緩存,關閉瀏覽器後,數據依然存在,此資源不會隨著該頁面的關閉而釋放掉下次打開仍然會是from disk cache。
304 Not Modified: 訪問伺服器,發現數據沒有更新,伺服器返回此狀態碼。然後從緩存中讀取數據。
在瀏覽器中,瀏覽器會在js和圖片等文件解析執行後直接存入內存緩存中,那麼當刷新頁面時只需直接從內存緩存中讀取(from memory cache);而css文件則會存入硬碟文件中,所以每次渲染頁面都需要從硬碟讀取緩存(from disk cache)。
內存緩存(from memory cache)和硬碟緩存(from disk cache)特點
(1)內存緩存(from memory cache):內存緩存具有兩個特點,分別是快速讀取和時效性:
1、快速讀取:內存緩存會將編譯解析後的文件,直接存入該進程的內存中,占據該進程一定的內存資源,以方便下次運行使用時的快速讀取。
2、時效性:一旦該進程關閉,則該進程的內存則會清空。
(2)硬碟緩存(from disk cache):硬碟緩存則是直接將緩存寫入硬碟文件中,讀取緩存需要對該緩存存放的硬碟文件進行I/O操作,然後重新解析該緩存內容,讀取復雜,速度比內存緩存慢。
緩存原理
1、先查找內存,如果內存中存在,從內存中載入;
2、如果內存中未查找到,選擇硬碟獲取,如果硬碟中有,從硬碟中載入;
3、如果硬碟中未查找到,那就進行網路請求;
4、載入到的資源緩存到硬碟和內存;
執行順序
現載入一種資源(例如:圖片):
訪問-> 200 -> 退出瀏覽器
重新進來-> 200(from disk cache) -> 刷新 -> 200(from memory cache)
附一張流程圖梳理一下
Ⅳ 談談RecyclerView中的緩存
Android深入理解RecyclerView的緩存機制
RecyclerView在項目中的使用已經很普遍了,可以說是項目中最高頻使用的一個控制項了。除了布局靈活性、豐富的動畫,RecyclerView還有優秀的緩存機制,本文嘗試通過源碼深入了解一下RecyclerView中的緩存機制。
RecyclerView做性能優化要說復雜也復雜,比如說布局優化,緩存,預載入等等。其優化的點很多,在這些看似獨立的點之間,其實存在一個樞紐:Adapter。因為所有的ViewHolder的創建和內容的綁定都需要經過Adaper的兩個函數onCreateViewHolder和onBindViewHolder。
因此我們性能優化的本質就是要減少這兩個函數的調用時間和調用的次數。如果我們想對RecyclerView做性能優化,必須清楚的了解到我們的每一步操作背後,onCreateViewHolder和onBindViewHolder調用了多少次。因此,了解RecyclerView的緩存機制是RecyclerView性能優化的基礎。
為了理解緩存的應用場景,本文首先會簡單介紹一下RecyclerView的繪制原理,然後再分析其緩存實現原理。
RecyclerView滑動時會觸發onTouchEvent#onMove,回收及復用ViewHolder在這里就會開始。我們知道設置RecyclerView時需要設置LayoutManager,LayoutManager負責RecyclerView的布局,包含對ItemView的獲取與復用。以LinearLayoutManager為例,當RecyclerView重新布局時會依次執行下面幾個方法:
上述的整個調用鏈:onLayoutChildren()->fill()->layoutChunk()->next()->getViewForPosition(),getViewForPosition()即是是從RecyclerView的回收機制實現類Recycler中獲取合適的View,下面主要就來從看這個Recycler#getViewForPosition()的實現。
上述邏輯用流程圖表示:
RecyclerView在Recyler裡面實現ViewHolder的緩存,Recycler裡面的實現緩存的主要包含以下5個對象:
public final class Recycler {
final ArrayList mAttachedScrap = new ArrayList<>();
ArrayList mChangedScrap = null;
RecyclerView在設計的時候講上述5個緩存對象分為了3級。每次創建ViewHolder的時候,會按照優先順序依次查詢緩存創建ViewHolder。每次講ViewHolder緩存到Recycler緩存的時候,也會按照優先順序依次緩存進去。三級緩存分別是:
使用自定義ViewCacheExtension後,view離屏後再回來不會走onBindViewHolder()方法。
holder.setIsRecyclable(false),這樣的話每次都會走onCreateViewHolder()和onBindViewHolder()方法
1.提前初始化viewHolder,放到緩存池中
viewPool.putRecycledView(adapter.onCreateViewHolder(recyclerView, 1))
2.提前初始化view,在onCreateViewHolder的時候去取view
3.自定義ViewCacheExtension
4.適當的增加cacheSize
4.公用緩存池,比如多個viewPager+fragment場景使用,或者全局單利緩存池,感覺用戶不大。
有2中做法有值
第一種
第二種
不會,因為prefetch(GapWorker中的一個方法)之後mViewCacheMax會變成mRequestedCacheMax + extraCache
有2種方式可以讓緩存失效
第一種
recyclerView.setItemViewCacheSize(-1)
第二種
recyclerView.setItemViewCacheSize(0)
layoutManager.isItemPrefetchEnabled = false
設置不緩存後,來回滑動讓view進入屏幕離開屏幕,viewHolder的item時會多次走onBindViewHolder()方法。