關(guān)于Spring中一級(jí)緩存、二級(jí)緩存和三級(jí)緩存的那些事
題記
常常聽(tīng)到別人提起:“一級(jí)緩存、二級(jí)緩存、三級(jí)緩存”。那么它們是什么呢?有什么作用呢?
緩存作用分析
Spring中的一級(jí)緩存名為singletonObjects,二級(jí)緩存名為earlySingletonObjects,三級(jí)緩存名為singletonFactories,除了一級(jí)緩存是ConcurrentHashMap之外,二級(jí)緩存和三級(jí)緩存都是HashMap。它們的定義是在DefaultSingletonBeanRegistry類中。

一級(jí)緩存-singletonObjects是用來(lái)存放就緒狀態(tài)的Bean。保存在該緩存中的Bean所實(shí)現(xiàn)Aware子接口的方法已經(jīng)回調(diào)完畢,自定義初始化方法已經(jīng)執(zhí)行完畢,也經(jīng)過(guò)BeanPostProcessor實(shí)現(xiàn)類的postProcessorBeforeInitialization、postProcessorAfterInitialization方法處理;
二級(jí)緩存-earlySingletonObjects是用來(lái)存放早期曝光的Bean,一般只有處于循環(huán)引用狀態(tài)的Bean才會(huì)被保存在該緩存中。保存在該緩存中的Bean所實(shí)現(xiàn)Aware子接口的方法還未回調(diào),自定義初始化方法未執(zhí)行,也未經(jīng)過(guò)BeanPostProcessor實(shí)現(xiàn)類的postProcessorBeforeInitialization、postProcessorAfterInitialization方法處理。如果啟用了Spring AOP,并且處于切點(diǎn)表達(dá)式處理范圍之內(nèi),那么會(huì)被增強(qiáng),即創(chuàng)建其代理對(duì)象。
這里額外提一點(diǎn),普通Bean被增強(qiáng)(JDK動(dòng)態(tài)代理或CGLIB)的時(shí)機(jī)是在AbstractAutoProxyCreator實(shí)現(xiàn)的BeanPostProcessor的postProcessorAfterInitialization方法中,而處于循環(huán)引用狀態(tài)的Bean被增強(qiáng)的時(shí)機(jī)是在AbstractAutoProxyCreator實(shí)現(xiàn)的SmartInstantiationAwareBeanPostProcessor的getEarlyBeanReference方法中。
三級(jí)緩存-singletonFactories是用來(lái)存放創(chuàng)建用于獲取Bean的工廠類-ObjectFactory實(shí)例。在IoC容器中,所有剛被創(chuàng)建出來(lái)的Bean,默認(rèn)都會(huì)保存到該緩存中。
Bean在這三個(gè)緩存之間的流轉(zhuǎn)順序?yàn)椋ù嬖谘h(huán)引用):
- 通過(guò)反射創(chuàng)建Bean實(shí)例。是單例Bean,并且IoC容器允許Bean之間循環(huán)引用,保存到三級(jí)緩存中。
- 當(dāng)發(fā)生了循環(huán)引用時(shí),從三級(jí)緩存中取出Bean對(duì)應(yīng)的ObjectFactory實(shí)例,調(diào)用其getObject方法,來(lái)獲取早期曝光Bean,從三級(jí)緩存中移除,保存到二級(jí)緩存中。
- Bean初始化完成,生命周期的相關(guān)方法執(zhí)行完畢,保存到一級(jí)緩存中,從二級(jí)緩存以及三級(jí)緩存中移除。
Bean在這三個(gè)緩存之間的流轉(zhuǎn)順序?yàn)椋](méi)有循環(huán)引用):
- 通過(guò)反射創(chuàng)建Bean實(shí)例。是單例Bean,并且IoC容器允許Bean之間循環(huán)引用,保存到三級(jí)緩存中。
- Bean初始化完成,生命周期的相關(guān)方法執(zhí)行完畢,保存到一級(jí)緩存中,從二級(jí)緩存以及三級(jí)緩存中移除。
簡(jiǎn)略流程圖:

一級(jí)緩存、二級(jí)緩存、三級(jí)緩存區(qū)別是什么
一級(jí)緩存、二級(jí)緩存、三級(jí)緩存是什么?作用?區(qū)別? 首先簡(jiǎn)單了解一下一級(jí)緩存。目前所有主流處理器大都具有一級(jí)緩存和二級(jí)緩存,少數(shù)高端處理器還集成了三級(jí)緩存。其中,一級(jí)緩存可分為一級(jí)指令緩存和一級(jí)數(shù)據(jù)緩存。一級(jí)指令緩存用于暫時(shí)存儲(chǔ)并向CPU遞送各類運(yùn)算指令;一級(jí)數(shù)據(jù)緩存用于暫時(shí)存儲(chǔ)并向CPU遞送運(yùn)算所需數(shù)據(jù),這就是一級(jí)緩存的作用。 那么,二級(jí)緩存的作用又是什么呢?簡(jiǎn)單地說(shuō),二級(jí)緩存就是一級(jí)緩存的緩沖器:一級(jí)緩存制造成本很高因此它的容量有限,二級(jí)緩存的作用就是存儲(chǔ)那些CPU處理時(shí)需要用到、一級(jí)緩存又無(wú)法存儲(chǔ)的數(shù)據(jù)。同樣道理,三級(jí)緩存和內(nèi)存可以看作是二級(jí)緩存的緩沖器,它們的容量遞增,但單位制造成本卻遞減。
需要注意的是,無(wú)論是二級(jí)緩存、三級(jí)緩存還是內(nèi)存都不能存儲(chǔ)處理器操作的原始指令,這些指令只能存儲(chǔ)在CPU的一級(jí)指令緩存中,而余下的二級(jí)緩存、三級(jí)緩存和內(nèi)存僅用于存儲(chǔ)CPU所需數(shù)據(jù)。 根據(jù)工作原理的不同,目前主流處理器所采用的一級(jí)數(shù)據(jù)緩存又可以分為實(shí)數(shù)據(jù)讀寫(xiě)緩存和數(shù)據(jù)代碼指令追蹤緩存2種,它們分別被AMD和Intel所采用。不同的一級(jí)數(shù)據(jù)緩存設(shè)計(jì)對(duì)于二級(jí)緩存容量的需求也各不相同,下面讓我們簡(jiǎn)單了解一下這兩種一級(jí)數(shù)據(jù)緩存設(shè)計(jì)的不同之處。
一、AMD一級(jí)數(shù)據(jù)緩存設(shè)計(jì) AMD采用的一級(jí)緩存設(shè)計(jì)屬于傳統(tǒng)的“實(shí)數(shù)據(jù)讀寫(xiě)緩存”設(shè)計(jì)?;谠摷軜?gòu)的一級(jí)數(shù)據(jù)緩存主要用于存儲(chǔ)CPU最先讀取的數(shù)據(jù);而更多的讀取數(shù)據(jù)則分別存儲(chǔ)在二級(jí)緩存和系統(tǒng)內(nèi)存當(dāng)中。做個(gè)簡(jiǎn)單的假設(shè),假如處理器需要讀取“AMD ATHLON 64 3000+ IS GOOD”這一串?dāng)?shù)據(jù)(不記空格),那么首先要被讀取的“AMDATHL”將被存儲(chǔ)在一級(jí)數(shù)據(jù)緩存中,而余下的“ON643000+ISGOOD”則被分別存儲(chǔ)在二級(jí)緩存和系統(tǒng)內(nèi)存當(dāng)中(如下圖所示)。 需要注意的是,以上假設(shè)只是對(duì)AMD處理器一級(jí)數(shù)據(jù)緩存的一個(gè)抽象描述,一級(jí)數(shù)據(jù)緩存和二級(jí)緩存所能存儲(chǔ)的數(shù)據(jù)長(zhǎng)度完全由緩存容量的大小決定,而絕非以上假設(shè)中的幾個(gè)字節(jié)。“實(shí)數(shù)據(jù)讀寫(xiě)緩存”的優(yōu)點(diǎn)是數(shù)據(jù)讀取直接快速,但這也需要一級(jí)數(shù)據(jù)緩存具有一定的容量,增加了處理器的制造難度(一級(jí)數(shù)據(jù)緩存的單位制造成本較二級(jí)緩存高)。
二、Intel一級(jí)數(shù)據(jù)緩存設(shè)計(jì) 自P4時(shí)代開(kāi)始,Intel開(kāi)始采用全新的“數(shù)據(jù)代碼指令追蹤緩存”設(shè)計(jì)?;谶@種架構(gòu)的一級(jí)數(shù)據(jù)緩存不再存儲(chǔ)實(shí)際的數(shù)據(jù),而是存儲(chǔ)這些數(shù)據(jù)在二級(jí)緩存中的指令代碼(即數(shù)據(jù)在二級(jí)緩存中存儲(chǔ)的起始地址)。假設(shè)處理器需要讀取“INTEL P4 IS GOOD”這一串?dāng)?shù)據(jù)(不記空格),那么所有數(shù)據(jù)將被存儲(chǔ)在二級(jí)緩存中,而一級(jí)數(shù)據(jù)代碼指令追蹤緩存需要存儲(chǔ)的僅僅是上述數(shù)據(jù)的起始地址。
由于一級(jí)數(shù)據(jù)緩存不再存儲(chǔ)實(shí)際數(shù)據(jù),因此“數(shù)據(jù)代碼指令追蹤緩存”設(shè)計(jì)能夠極大地降CPU對(duì)一級(jí)數(shù)據(jù)緩存容量的要求,降低處理器的生產(chǎn)難度。但這種設(shè)計(jì)的弊端在于數(shù)據(jù)讀取效率較“實(shí)數(shù)據(jù)讀寫(xiě)緩存設(shè)計(jì)”低,而且對(duì)二級(jí)緩存容量的依賴性非常大。 在了解了一級(jí)緩存、二級(jí)緩存的大致作用及其分類以后,下面我們來(lái)回答以下硬件一菜鳥(niǎo)網(wǎng)友提出的問(wèn)題。
從理論上講,二級(jí)緩存越大處理器的性能越好,但這并不是說(shuō)二級(jí)緩存容量加倍就能夠處理器帶來(lái)成倍的性能增長(zhǎng)。目前CPU處理的絕大部分?jǐn)?shù)據(jù)的大小都在0-256KB之間,小部分?jǐn)?shù)據(jù)的大小在256KB-512KB之間,只有極少數(shù)數(shù)據(jù)的大小超過(guò)512KB。所以只要處理器可用的一級(jí)、二級(jí)緩存容量達(dá)到256KB以上,那就能夠應(yīng)付正常的應(yīng)用;512KB容量的二級(jí)緩存已經(jīng)足夠滿足絕大多數(shù)應(yīng)用的需求。 這其中,對(duì)于采用“實(shí)數(shù)據(jù)讀寫(xiě)緩存”設(shè)計(jì)的AMD Athlon 64、Sempron處理器而言,由于它們已經(jīng)具備了64KB一級(jí)指令緩存和64KB一級(jí)數(shù)據(jù)緩存,只要處理器的二級(jí)緩存容量大于等于128KB就能夠存儲(chǔ)足夠的數(shù)據(jù)和指令,因此它們對(duì)二級(jí)緩存的依賴性并不大。這就是為什么主頻同為1.8GHz的Socket 754 Sempron 3000+(128KB二級(jí)緩存)、Sempron 3100+(256KB二級(jí)緩存)以及Athlon 64 2800+(512KB二級(jí)緩存)在大多數(shù)評(píng)測(cè)中性能非常接近的主要原因。所以對(duì)于普通用戶而言754 Sempron 2600+是值得考慮的。 反觀Intel目前主推的P4、賽揚(yáng)系列處理器,它們都采用了“數(shù)據(jù)代碼指令追蹤緩存”架構(gòu),其中Prescott內(nèi)核的一級(jí)緩存中只包含了12KB一級(jí)指令緩存和16KB一級(jí)數(shù)據(jù)緩存,而Northwood內(nèi)核更是只有12KB一級(jí)指令緩存和8KB一級(jí)數(shù)據(jù)緩存。
因此,P4、賽隆系列處理器非常依賴于二級(jí)緩存,賽揚(yáng)D 320(256KB二級(jí)緩存)和賽揚(yáng)2.4GHz(128kb二級(jí)緩存)的性能差距是很好的證明;Cayon D和P4E處理器之間的性能差距也非常明顯。最后,如果你是一個(gè)狂熱的游戲愛(ài)好者或者一個(gè)專業(yè)的多媒體用戶,一個(gè)帶有1MB二級(jí)緩存的P4處理器和一個(gè)512Kb/1MB二級(jí)緩存的Athon 64處理器是你的理想選擇。由于CPU的主存和二級(jí)緩存在重計(jì)算負(fù)載下幾乎是“滿”的,大的二級(jí)緩存可以為處理器提供大約5%到10%的性能改進(jìn),這對(duì)于要求苛刻的用戶是絕對(duì)必要的。一級(jí)緩存是在CPU內(nèi)的,用來(lái)存放內(nèi)部指令,2級(jí)緩存和CPU封裝在一起,也是用來(lái)存放指令數(shù)據(jù)的,三級(jí)和四級(jí)緩存只在高端的服務(wù)器CPU里有,作用差不多,速度更快,更穩(wěn)定,更有效 并不是緩存越大越好,譬如AMD和INTER就有不同的理論,AMD認(rèn)為一級(jí)緩存越大越好,所以一級(jí)比較大,而INTER認(rèn)為過(guò)大會(huì)有更長(zhǎng)的指令執(zhí)行時(shí)間,所以一級(jí)很小,二級(jí)緩存那兩個(gè)公司的理論又反過(guò)來(lái)了,AMD的小,INTER的大,一般主流的INTERCPU的2級(jí)緩存都在2M左右 我們通常用(L1,L2)來(lái)稱呼緩存又叫高速緩沖存儲(chǔ)器其作用在于緩解主存速度慢、跟不上CPU讀寫(xiě)速度要求的矛盾。它的實(shí)現(xiàn)原理,是把CPU最近最可能用到的少量信息(數(shù)據(jù)或指令)從主存復(fù)制到CACHE中,當(dāng)CPU下次再用這些信息時(shí),它就不必訪問(wèn)慢速的主存,而直接從快速的CACHE中得到,從而提高了得到這些信息的速度,使CPU有更高的運(yùn)行效率。
總結(jié)
通過(guò)以上分析,我們可以得知Bean在一級(jí)緩存、二級(jí)緩存、三級(jí)緩存中的流轉(zhuǎn)順序?yàn)椋喝?jí)緩存->二級(jí)緩存->一級(jí)緩存。但是并不是所有Bean都會(huì)經(jīng)歷這個(gè)過(guò)程,例如對(duì)于原型Bean(Prototype),IoC容器不會(huì)將其保存到任何一個(gè)緩存中的,另外即便是單例Bean(Singleton),如果沒(méi)有循環(huán)引用關(guān)系,也不會(huì)被保存到二級(jí)緩存中的。
到此這篇關(guān)于關(guān)于Spring中一級(jí)緩存、二級(jí)緩存和三級(jí)緩存的那些事的文章就介紹到這了,更多相關(guān)Spring一級(jí)緩存、二級(jí)緩存和三級(jí)緩存內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
解決idea中java出現(xiàn)無(wú)效的源發(fā)行版問(wèn)題
這篇文章主要給大家介紹了關(guān)于解決idea中java出現(xiàn)無(wú)效的源發(fā)行版問(wèn)題的相關(guān)資料,無(wú)效的源發(fā)行版是指IntelliJ IDEA無(wú)法正確識(shí)別和處理的源代碼版本,這可能是由于錯(cuò)誤的配置、缺少依賴項(xiàng)、不兼容的插件或其他問(wèn)題導(dǎo)致的,需要的朋友可以參考下2024-01-01
解決Springboot獲取不到nacos配置中心的配置問(wèn)題
由于項(xiàng)目使用的nacos老版本,存在風(fēng)險(xiǎn)bug, 需要將nacos升級(jí)至2.2.1及以上版本,版本升級(jí)完畢之后 啟動(dòng)項(xiàng)目發(fā)現(xiàn)項(xiàng)目開(kāi)始報(bào)錯(cuò),所以本文記錄一下Springboot獲取不到nacos配置中心的配置問(wèn)題,文中有詳細(xì)的解決方法,需要的朋友可以參考下2023-09-09
java實(shí)現(xiàn)代碼統(tǒng)計(jì)小程序
這篇文章主要為大家詳細(xì)介紹了java實(shí)現(xiàn)代碼統(tǒng)計(jì)小程序,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-09-09
Java使用XML與注解方式實(shí)現(xiàn)CRUD操作代碼
MyBatis提供了靈活的配置和使用方式,使得數(shù)據(jù)庫(kù)操作更加簡(jiǎn)潔和高效,通過(guò)本文,我們介紹了如何使用MyBatis框架,通過(guò)XML映射文件和注解兩種方式來(lái)實(shí)現(xiàn)數(shù)據(jù)庫(kù)的增刪改查操作,感興趣的朋友跟隨小編一起看看吧2024-02-02
springboot整合sentinel接口熔斷的實(shí)現(xiàn)示例
為了防止慢接口導(dǎo)致的服務(wù)阻塞,可以通過(guò)添加熔斷處理來(lái)避免應(yīng)用的大量工作線程陷入阻塞,保證其他接口的正常運(yùn)行,本文介紹了如何使用Spring Boot與Sentinel進(jìn)行接口熔斷的配置與實(shí)現(xiàn),感興趣的可以了解一下2024-09-09
MyBatis Map結(jié)果的Key轉(zhuǎn)為駝峰式
今天小編就為大家分享一篇關(guān)于MyBatis Map結(jié)果的Key轉(zhuǎn)為駝峰式,小編覺(jué)得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來(lái)看看吧2018-12-12
JAVA復(fù)制數(shù)組和重置數(shù)組大小操作
這篇文章主要介紹了JAVA復(fù)制數(shù)組和重置數(shù)組大小操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-09-09

