.課程網(wǎng)站
CPU多級(jí)緩存
????左圖為最簡單的高速緩存的配置,數(shù)據(jù)的讀取和存儲(chǔ)都經(jīng)過高速緩存,CPU核心與高速緩存有一條特殊的快速通道;主存與高速緩存都連在系統(tǒng)總線上(BUS)這條總線還用于其他組件的通信
????在高速緩存出現(xiàn)后不久,系統(tǒng)變得越來越復(fù)雜,高速緩存與主存之間的速度差異被拉大,直到加入了另一級(jí)緩存,新加入的這級(jí)緩存比第一緩存更大,并且更慢,而且經(jīng)濟(jì)上不合適,所以有了二級(jí)緩存,甚至是三級(jí)緩存

1.為什么需要CPU cache?
????CPU的頻率太快了,快到主存跟不上,這樣在處理器時(shí)鐘周期內(nèi),CPU常常需要等待主存,浪費(fèi)資源。? 所以cache的出現(xiàn),是為了緩解CPU和內(nèi)存之間速度的不匹配問題(結(jié)構(gòu):cpu->cache->memory)。
2.CPU cache 存在的原理?
局部性原理:CPU 訪問存儲(chǔ)器時(shí),無論是存取指令還是存取數(shù)據(jù),所訪問的存取單元都趨于聚集在一個(gè)較小的連續(xù)區(qū)域中。
時(shí)間局部性:如果某個(gè)數(shù)據(jù)被訪問,那么在不久的將來他很可能被再次訪問。
空間局部性:如果某個(gè)數(shù)據(jù)被訪問,那么與他相鄰的數(shù)據(jù)很快也可能被訪問。
3.緩存一致性(MESI)
????MESI協(xié)議中cache line數(shù)據(jù)狀態(tài)有4種,引起數(shù)據(jù)狀態(tài)轉(zhuǎn)換的CPU cache操作也有4種,因此要理解MESI協(xié)議,就要將這16種狀態(tài)轉(zhuǎn)換的情況討論清楚。

?初始場景:在最初的時(shí)候,所有的CPU中都沒有數(shù)據(jù),其中一個(gè)CPU發(fā)生讀操作,此時(shí)發(fā)生RR(數(shù)據(jù)從主內(nèi)存中讀取到當(dāng)前CPU的cache),狀態(tài)為E(獨(dú)占,只有當(dāng)前CPU有數(shù)據(jù),并且和主存一致)。此時(shí),如果有其他CPU也讀取主存數(shù)據(jù),則狀態(tài)修改為S(共享,多個(gè)CPU之間擁有相同數(shù)據(jù),并且和主存保持一致),如果其中一個(gè)CPU發(fā)生數(shù)據(jù)修改,那么該CPU中數(shù)據(jù)狀態(tài)修改為M(擁有最新數(shù)據(jù),和主存不一致,但是以當(dāng)前CPU中的數(shù)據(jù)為準(zhǔn)),并通知其他擁有該數(shù)據(jù)的CPU數(shù)據(jù)失效,其他CPU中的cache line狀態(tài)修改為I(失效,和主存中的數(shù)據(jù)被認(rèn)為不一致,數(shù)據(jù)不可用應(yīng)該重新獲?。?/p>
modify
? ? 場景:當(dāng)前CPU中數(shù)據(jù)狀態(tài)是modify,表示當(dāng)前CPU中擁有最新數(shù)據(jù),雖然主存中的數(shù)據(jù)和當(dāng)前CPU中的數(shù)據(jù)不一致,但是以當(dāng)前CPU中的數(shù)據(jù)為準(zhǔn);
? ? LR:此時(shí)如果發(fā)生local read,即當(dāng)前CPU讀數(shù)據(jù),直接從cache中獲取數(shù)據(jù),擁有最新數(shù)據(jù),因此狀態(tài)不變;
? ??LW:直接修改本地cache數(shù)據(jù),修改后也是當(dāng)前CPU擁有最新數(shù)據(jù),因此狀態(tài)不變;
? ??RR:因?yàn)楸镜貎?nèi)存中有最新數(shù)據(jù),因此當(dāng)前CPU不會(huì)發(fā)生RR和RW,當(dāng)本地cache控制器監(jiān)聽到總線上有RR發(fā)生的時(shí),必然是其他CPU發(fā)生了讀主存的操作,此時(shí)為了保證一致性, 當(dāng)前CPU應(yīng)該將數(shù)據(jù)寫回主存,而隨后的RR將會(huì)使得其他CPU和當(dāng)前CPU擁有共同的數(shù)據(jù),因此狀態(tài)修改為S;
? ??RW(將當(dāng)前CPU緩存中的數(shù)據(jù)寫入到主內(nèi)存里面):同RR,當(dāng)cache控制器監(jiān)聽到總線發(fā)生RW,當(dāng)前CPU會(huì)將數(shù)據(jù)寫回主存,因?yàn)殡S后的RW將會(huì)導(dǎo)致主存的數(shù)據(jù)修改,因此狀態(tài)修改成I;
exclusive
????場景:當(dāng)前CPU中的數(shù)據(jù)狀態(tài)是exclusive,表示當(dāng)前CPU獨(dú)占數(shù)據(jù)(其他CPU沒有數(shù)據(jù)),并且和主存的數(shù)據(jù)一致;
? ? LR:從本地cache中直接獲取數(shù)據(jù),狀態(tài)不變;
? ? LW:修改本地cache中的數(shù)據(jù),狀態(tài)修改成M(因?yàn)槠渌鸆PU中并沒有該數(shù)據(jù),因此不存在共享問題,不需要通知其他CPU修改cache line的狀態(tài)為I);
? ? RR:因?yàn)楸镜豤ache中有最新數(shù)據(jù),因此當(dāng)前CPU cache操作不會(huì)發(fā)生RR和RW,當(dāng)cache控制器監(jiān)聽到總線上發(fā)生RR的時(shí)候,必然是其他CPU發(fā)生了讀取主存的操作,而RR操作不會(huì)導(dǎo)致數(shù)據(jù)修改,因此兩個(gè)CPU中的數(shù)據(jù)和主存中的數(shù)據(jù)一致,此時(shí)cache line狀態(tài)修改為S;
? ? RW:同RR,當(dāng)cache控制器監(jiān)聽到總線發(fā)生RW,發(fā)生其他CPU將最新數(shù)據(jù)寫回到主存,此時(shí)為了保證緩存一致性,當(dāng)前CPU的數(shù)據(jù)狀態(tài)修改為I;
shared
????場景:當(dāng)前CPU中的數(shù)據(jù)狀態(tài)是shared,表示當(dāng)前CPU和其他CPU共享數(shù)據(jù),且數(shù)據(jù)在多個(gè)CPU之間一致、多個(gè)CPU之間的數(shù)據(jù)和主存一致;
? ? LR:直接從cache中讀取數(shù)據(jù),狀態(tài)不變;
? ? LW:發(fā)生本地寫,并不會(huì)將數(shù)據(jù)立即寫回主存,而是在稍后的一個(gè)時(shí)間再寫回主存,因此為了保證緩存一致性,當(dāng)前CPU的cache line狀態(tài)修改為M,并通知其他擁有該數(shù)據(jù)的CPU該數(shù)據(jù)失效,其他CPU將cache line狀態(tài)修改為I;
? ? RR:狀態(tài)不變,因?yàn)槎鄠€(gè)CPU中的數(shù)據(jù)和主存一致;
? ? RW:當(dāng)監(jiān)聽到總線發(fā)生了RW,意味著其他CPU發(fā)生了寫主存操作,此時(shí)本地cache中的數(shù)據(jù)既不是最新數(shù)據(jù),和主存也不再一致,因此當(dāng)前CPU的cache line狀態(tài)修改為I;
invalid
????場景:當(dāng)前CPU中的數(shù)據(jù)狀態(tài)是invalid,表示當(dāng)前CPU中是臟數(shù)據(jù),不可用,其他CPU可能有數(shù)據(jù)、也可能沒有數(shù)據(jù);
? ? LR:因?yàn)楫?dāng)前CPU的cache line數(shù)據(jù)不可用,因此會(huì)發(fā)生RR操作,此時(shí)的情形如下。
? ? ? ? A. 如果其他CPU中無數(shù)據(jù)則狀態(tài)修改為E;
? ? ? ? B. 如果其他CPU中有數(shù)據(jù)且狀態(tài)為S或E則狀態(tài)修改為S;
? ? ? ? C. 如果其他CPU中有數(shù)據(jù)且狀態(tài)為M,那么其他CPU首先發(fā)生RW將M狀態(tài)的數(shù)據(jù)寫回主存并修改狀態(tài)為S,隨后當(dāng)前CPU讀取主存數(shù)據(jù),也將狀態(tài)修改為S;
? ? LW:因?yàn)楫?dāng)前CPU的cache line數(shù)據(jù)無效,因此發(fā)生LW會(huì)直接操作本地cache,此時(shí)的情形如下。
? ? ? ? A. 如果其他CPU中無數(shù)據(jù),則將本地cache line的狀態(tài)修改為M;
? ? ? ? B. 如果其他CPU中有數(shù)據(jù)且狀態(tài)為S或E,則修改本地cache,通知其他CPU將數(shù)據(jù)修改為I,當(dāng)前CPU中的cache line狀態(tài)修改為M;
? ? ? ? C. 如果其他CPU中有數(shù)據(jù)且狀態(tài)為M,則其他CPU首先將數(shù)據(jù)寫回主存,并將狀態(tài)修改為I,當(dāng)前CPU中的cache line狀態(tài)修改為M;
? ? RR:監(jiān)聽到總線發(fā)生RR操作,表示有其他CPU讀取內(nèi)存,和本地cache無關(guān),狀態(tài)不變;
? ? RW:監(jiān)聽到總線發(fā)生RW操作,表示有其他CPU寫主存,和本地cache無關(guān),狀態(tài)不變;
總結(jié): MESI協(xié)議為了保證多個(gè)CPU cache中共享數(shù)據(jù)的一致性,定義了cache line的四種狀態(tài),而CPU對(duì)cache的4種操作可能會(huì)產(chǎn)生不一致狀態(tài),因此cache控制器監(jiān)聽到本地操作和遠(yuǎn)程操作的時(shí)候, 需要對(duì)地址一致的cache line狀態(tài)做出一定的修改,從而保證數(shù)據(jù)在多個(gè)cache之間流轉(zhuǎn)的一致性。
Java內(nèi)存模型
????Java線程之間的通信采用的是共享內(nèi)存模型,這里提到的共享內(nèi)存模型指的是Java內(nèi)存模型(簡稱JMM),JMM決定一個(gè)線程對(duì)共享變量的寫入何時(shí)對(duì)另一個(gè)線程可見。從抽象的角度來看,JMM定義了線程和主存之間的抽象關(guān)系:線程之間的共享變量存儲(chǔ)在主存中(main memory)中,每個(gè)線程都有一個(gè)私有的本地內(nèi)存(local memory),本地內(nèi)存中存儲(chǔ)了該線程以讀/寫共享變量的副本。本地內(nèi)存是JMM的一個(gè)抽象概念,并不真實(shí)存在。它涵蓋了緩存,寫緩沖區(qū),寄存器以及其他的硬件和編譯器優(yōu)化。

JVM對(duì)Java內(nèi)存模型的實(shí)現(xiàn)
在JVM內(nèi)部,Java內(nèi)存模型把內(nèi)存分成了兩部分:線程棧區(qū)、堆區(qū)和方法區(qū),下圖展示了Java內(nèi)存模型在JVM中的邏輯視圖:?

? ? 基本類型變量和對(duì)象的引用,會(huì)被存儲(chǔ)到棧區(qū)。?
? ? 對(duì)象的實(shí)例存放在堆區(qū)中。
????Static類型的變量以及類本身相關(guān)信息都會(huì)隨著類本身存儲(chǔ)在方法區(qū)。
????堆中的對(duì)象和方法區(qū)的數(shù)據(jù)可以被多線程共享。如果一個(gè)線程獲得一個(gè)對(duì)象的應(yīng)用,它便可訪問這個(gè)對(duì)象的成員變量。如果兩個(gè)線程同時(shí)調(diào)用了同一個(gè)對(duì)象的同一個(gè)方法,那么這兩個(gè)線程便可同時(shí)訪問這個(gè)對(duì)象的成員變量,但是對(duì)于本地(局部)變量,每個(gè)線程都會(huì)拷貝一份到自己的線程棧中,即不存在多線程競爭同一個(gè)資源的問題。
? ? 垃圾回收器GC的工作區(qū)域是在堆中,會(huì)不定時(shí)去清除引用不可達(dá)的對(duì)象。

硬件內(nèi)存架構(gòu)
????現(xiàn)代計(jì)算機(jī)一般都有2個(gè)以上CPU,而且每個(gè)CPU還有可能包含多個(gè)核心。因此,如果我們的應(yīng)用是多線程的話,這些線程可能會(huì)在各個(gè)CPU核心中并行運(yùn)行。
????在CPU內(nèi)部有一組CPU寄存器,也就是CPU的儲(chǔ)存器。CPU操作寄存器的速度要比操作計(jì)算機(jī)主存快得多。在主存和CPU寄存器之間還存在CPU緩存,CPU操作CPU緩存的速度快于主存但慢于CPU寄存器。某些CPU可能有多個(gè)緩存層(一級(jí)緩存和二級(jí)緩存)。計(jì)算機(jī)的主存也稱作RAM,所有的CPU都能夠訪問主存,而且主存比上面提到的緩存和寄存器大很多。
????當(dāng)一個(gè)CPU需要訪問主存時(shí),會(huì)先讀取一部分主存數(shù)據(jù)到CPU緩存中,進(jìn)而再讀取CPU緩存到寄存器。當(dāng)CPU需要寫數(shù)據(jù)到主存時(shí),同樣會(huì)先flush寄存器到CPU緩存,然后在某個(gè)時(shí)間節(jié)點(diǎn)緩存數(shù)據(jù)會(huì)flush到主存。

計(jì)算機(jī)指令的執(zhí)行流程
CPU 是由三個(gè)組件組成的:存儲(chǔ)器(高速緩存)、運(yùn)算器、控制器。計(jì)算機(jī)指令的執(zhí)行,都是在 CUP 的三個(gè)組件間流轉(zhuǎn)的??刂破髦饕ǔ绦蛴?jì)數(shù)器和指令寄存器。


1. 存儲(chǔ)器緩存數(shù)據(jù)和指令。
2. 從程序計(jì)數(shù)器中取出將要執(zhí)行的指令地址。
3. 總線通過指令地址到存儲(chǔ)器中取出對(duì)應(yīng)操作碼和地址碼,并放入指令寄存器中。
4. 將指令發(fā)送到指令譯碼器中。
5. 程序計(jì)數(shù)器+1,指向下一個(gè)要執(zhí)行的指令地址。
6. 譯碼器對(duì)指令進(jìn)行譯碼。
7. 譯碼器完成譯碼后,向運(yùn)算器發(fā)送控制信號(hào)。
8. 運(yùn)算器接收到控制信號(hào)后,執(zhí)行指令。