缓存流程图
Ⅰ 浏览器缓存和服务器缓存
一、浏览器缓存
浏览器缓存即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()方法。