Java 理解CPU緩存(CPU Cache)

從Java視角理解系統結構連載, 關注我的微博(鏈接)了解最新動態?

眾所周知, CPU是計算機的大腦, 它負責執行程序的指令; 內存負責存數據, 包括程序自身數據. 同樣大家都知道, 內存比CPU慢很多. 其實在30年前, CPU的頻率和內存總線的頻率在同一個級別, 訪問內存只比訪問CPU寄存器慢一點兒. 由于內存的發展都到技術及成本的限制, 現在獲取內存中的一條數據大概需要200多個CPU周期(CPU cycles), 而CPU寄存器一般情況下1個CPU周期就夠了.?

CPU緩存?
網頁瀏覽器為了加快速度,會在本機存緩存以前瀏覽過的數據; 傳統數據庫或NoSQL數據庫為了加速查詢, 常在內存設置一個緩存, 減少對磁盤(慢)的IO. 同樣內存與CPU的速度相差太遠, 于是CPU設計者們就給CPU加上了緩存(CPU Cache). 如果你需要對同一批數據操作很多次, 那么把數據放至離CPU更近的緩存, 會給程序帶來很大的速度提升. 例如, 做一個循環計數, 把計數變量放到緩存里,就不用每次循環都往內存存取數據了. 下面是CPU Cache的簡單示意圖.??
?
隨著多核的發展, CPU Cache分成了三個級別: L1, L2, L3. 級別越小越接近CPU, 所以速度也更快, 同時也代表著容量越小. L1是最接近CPU的, 它容量最小, 例如32K, 速度最快,每個核上都有一個L1 Cache(準確地說每個核上有兩個L1 Cache, 一個存數據 L1d Cache, 一個存指令 L1i Cache). L2 Cache 更大一些,例如256K, 速度要慢一些, 一般情況下每個核上都有一個獨立的L2 Cache; L3 Cache是三級緩存中最大的一級,例如12MB,同時也是最慢的一級, 在同一個CPU插槽之間的核共享一個L3 Cache.?

從CPU到大約需要的CPU周期大約需要的時間(單位ns)
寄存器1 cycle?
L1 Cache~3-4 cycles~0.5-1 ns
L2 Cache~10-20 cycles~3-7 ns
L3 Cache~40-45 cycles~15 ns
跨槽傳輸?~20 ns
內存~120-240 cycles~60-120ns

感興趣的同學可以在Linux下面用cat /proc/cpuinfo, 或Ubuntu下lscpu看看自己機器的緩存情況, 更細的可以通過以下命令看看:?
Shell代碼??收藏代碼
  1. $?cat?/sys/devices/system/cpu/cpu0/cache/index0/size??
  2. 32K??
  3. $?cat?/sys/devices/system/cpu/cpu0/cache/index0/type??
  4. Data??
  5. $?cat?/sys/devices/system/cpu/cpu0/cache/index0/level???
  6. 1??
  7. $?cat?/sys/devices/system/cpu/cpu3/cache/index3/level?????
  8. 3??

就像數據庫cache一樣, 獲取數據時首先會在最快的cache中找數據, 如果沒有命中(Cache miss) 則往下一級找, 直到三層Cache都找不到,那只要向內存要數據了. 一次次地未命中,代表取數據消耗的時間越長.?

緩存行(Cache line)?
為了高效地存取緩存, 不是簡單隨意地將單條數據寫入緩存的.? 緩存是由緩存行組成的, 典型的一行是64字節. 讀者可以通過下面的shell命令,查看cherency_line_size就知道知道機器的緩存行是多大.?
Shell代碼??收藏代碼
  1. $?cat?/sys/devices/system/cpu/cpu0/cache/index0/coherency_line_size???
  2. 64??

CPU存取緩存都是按行為最小單位操作的. 在這兒我將不提及緩存的associativity問題, 將問題簡化一些. 一個Java long型占8字節, 所以從一條緩存行上你可以獲取到8個long型變量. 所以如果你訪問一個long型數組, 當有一個long被加載到cache中, 你將無消耗地加載了另外7個. 所以你可以非常快地遍歷數組.?

實驗及分析?
我們在Java編程時, 如果不注意CPU Cache, 那么將導致程序效率低下. 例如以下程序, 有一個二維long型數組, 在我的32位筆記本上運行時的內存分布如圖:?
?
32位機器中的java的數組對象頭共占16字節(詳情見?鏈接), 加上62個long型一行long數據一共占512字節. 所以這個二維數據是順序排列的.?
Java代碼??收藏代碼
  1. public?class?L1CacheMiss?{??
  2. ????private?static?final?int?RUNS?=?10;??
  3. ????private?static?final?int?DIMENSION_1?=?1024?*?1024;??
  4. ????private?static?final?int?DIMENSION_2?=?62;??
  5. ??
  6. ????private?static?long[][]?longs;??
  7. ??
  8. ????public?static?void?main(String[]?args)?throws?Exception?{??
  9. ????????Thread.sleep(10000);??
  10. ????????longs?=?new?long[DIMENSION_1][];??
  11. ????????for?(int?i?=?0;?i?<?DIMENSION_1;?i++)?{??
  12. ????????????longs[i]?=?new?long[DIMENSION_2];??
  13. ????????????for?(int?j?=?0;?j?<?DIMENSION_2;?j++)?{??
  14. ????????????????longs[i][j]?=?0L;??
  15. ????????????}??
  16. ????????}??
  17. ????????System.out.println("starting....");??
  18. ??
  19. ????????final?long?start?=?System.nanoTime();??
  20. ????????long?sum?=?0L;??
  21. ????????for?(int?r?=?0;?r?<?RUNS;?r++)?{??
  22. //??????????for?(int?j?=?0;?j?<?DIMENSION_2;?j++)?{??
  23. //??????????????for?(int?i?=?0;?i?<?DIMENSION_1;?i++)?{??
  24. //??????????????????sum?+=?longs[i][j];??
  25. //??????????????}??
  26. //??????????}??
  27. ??
  28. ????????????for?(int?i?=?0;?i?<?DIMENSION_1;?i++)?{??
  29. ????????????????for?(int?j?=?0;?j?<?DIMENSION_2;?j++)?{??
  30. ????????????????????sum?+=?longs[i][j];??
  31. ????????????????}??
  32. ????????????}??
  33. ????????}??
  34. ????????System.out.println("duration?=?"?+?(System.nanoTime()?-?start));??
  35. ????}??
  36. }??

編譯后運行,結果如下?
Shell代碼??收藏代碼
  1. $?java?L1CacheMiss???
  2. starting....??
  3. duration?=?1460583903??

然后我們將22-26行的注釋取消, 將28-32行注釋, 編譯后再次運行,結果是不是比我們預想得還糟??
Shell代碼??收藏代碼
  1. $?java?L1CacheMiss???
  2. starting....??
  3. duration?=?22332686898??

前面只花了1.4秒的程序, 只做一行的對調要運行22秒. 從上節我們可以知道在加載longs[i][j]時, longs[i][j+1]很可能也會被加載至cache中, 所以立即訪問longs[i][j+1]將會命中L1 Cache, 而如果你訪問longs[i+1][j]情況就不一樣了, 這時候很可能會產生 cache miss導致效率低下.?
下面我們用perf來驗證一下,先將快的程序跑一下.?
Shell代碼??收藏代碼
  1. $?perf?stat?-e?L1-dcache-load-misses?java?L1CacheMiss???
  2. starting....??
  3. duration?=?1463011588??
  4. ??
  5. ?Performance?counter?stats?for?'java?L1CacheMiss':??
  6. ??
  7. ???????164,625,965?L1-dcache-load-misses?????????????????????????????????????????
  8. ??
  9. ??????13.273572184?seconds?time?elapsed??

一共164,625,965次L1 cache miss, 再看看慢的程序?
Shell代碼??收藏代碼
  1. $?perf?stat?-e?L1-dcache-load-misses?java?L1CacheMiss???
  2. starting....??
  3. duration?=?21095062165??
  4. ??
  5. ?Performance?counter?stats?for?'java?L1CacheMiss':??
  6. ??
  7. ?????1,421,402,322?L1-dcache-load-misses?????????????????????????????????????????
  8. ??
  9. ??????32.894789436?seconds?time?elapsed??

這回產生了1,421,402,322次 L1-dcache-load-misses, 所以慢多了.?

以上我只是示例了在L1 Cache滿了之后才會發生的cache miss. 其實cache miss的原因有下面三種:?
1. 第一次訪問數據, 在cache中根本不存在這條數據, 所以cache miss, 可以通過prefetch解決.?
2. cache沖突, 需要通過補齊來解決.?
3. 就是我示例的這種, cache滿, 一般情況下我們需要減少操作的數據大小, 盡量按數據的物理順序訪問數據.?
具體的信息可以參考這篇論文.?

轉載于:https://www.cnblogs.com/kool/p/6695727.html

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/375173.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/375173.shtml
英文地址,請注明出處:http://en.pswp.cn/news/375173.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

測試指令TEST

測試指令TESTTEST OPRD1,OPRD2 ;按位與操作,但不保存結果,僅影響標志寄存器,根據影響的標志位得到結果 該指令通常用于檢測某些位是否為1,但不改變原操作值.根據ZF得知判斷結果 mov al,01100011B;檢測位6是否為1,如果為1那么ZF0,如果為0那么ZF1 TEST AL,01000000B ;AL010000…

Homebrew OS X 不可或缺的套件管理器

Homebrew OS X 不可或缺的套件管理器,可以說Homebrew就是mac下的apt-get、yum. 1.安裝homebrew brew的安裝很簡單&#xff0c;使用一條ruby命令即可&#xff0c;Mac系統上已經默認安裝了ruby。 ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install…

【BZOJ】【1003】【ZJOI2006】物流運輸trans

最短路/DP 這題數據規模并不大&#xff01;&#xff01;這是重點……… 所以直接暴力DP就好了&#xff1a;f[i]表示前 i 天的最小花費&#xff0c;則有$f[i]min\{f[j]cost[j1][i]k\} (0\leq j \leq i-1)$其中cost數組表示第L天到第R天只用一種運輸方案連續運$R-L1$天的最小代價…

與操作指令AND

邏輯”與”操作指令AND(邏輯乘法) 0*000*101*001*11 只當參與運算的邏輯變量都同時取值為1時&#xff0c;其邏輯乘積才等于1。 MOV AL,01100011BAND AL,11111110B ;按位根據乘法表計算;結果AL01100010B另一種說法是用”0”來把相應位設置成0MOV AL,01100011B ;把AL的高4位設置成…

SVN-鉤子

先說說鉤子是干什么的吧&#xff0c;&#xff0c;簡單的說&#xff0c;svn鉤子就是在提交svn時前后所要觸發的事件&#xff0c;于是我們可以用鉤子做一些提交時的限制&#xff0c;及提交后的操作。最常用的一般有兩個&#xff0c;pre-commit,post-commit。下面分別簡單說下概念…

數據庫---T-SQL語句(一)

一、T-SQL語句 1.創建表:create table Name(Code varchar(50),) 主鍵&#xff1a;primary key 自增長&#xff1a;auto_increment 外鍵關系&#xff1a;references 非空&#xff1a;not null 2.刪除表&#xff1a;drop table family 3.創建數據庫&#xff1a;creat database…

或操作指令OR

邏輯”或”操作指令OR(邏輯加法) 000011101111 在給定的邏輯變量中&#xff0c;A或B只要有一個為1&#xff0c;其邏輯加的結果為1&#xff1b;兩者都為1則邏輯加為1。 MOV AL,01100011BOR AL,10000000B ;按位根據加法表進行運算;結果AL 11100011B另一種說法是用1將相應位設為1M…

Java學習筆記---繼承和super的用法

自從換了個視頻教學,感覺比原來那個好多了,就是學校網速太渣,好多視頻看一會卡半天,只能先看看已經下載的了. 不過也好,雖然不能從開始開始重新開,但是已經看過一次,在看一次也是好的,就當鞏固學習了. 繼承的關鍵字:extends 格式如下: class 子類名 extends父類名{ ... } 例如 …

html適配Anroid手機

本文全然是翻譯與總結谷歌官方的教程&#xff0c;已確保文檔的正確性。 免得大家被五花八門的其它的資料弄混了&#xff0c;也沒有系統行的學習。 一、設置窗體尺寸和適配屏幕分辨率 谷歌官方文檔提到兩個大的方面。 1.Viewport視圖窗體 這個是html中設置的。主要是設置高度和寬…

算術運算與邏輯運算

邏輯運算又稱布爾運算,取值只有兩個真或假,二進制數1和0在邏輯上可以代表真與假,是與否 算術運算...小學就開始學的了 兩者的區別在與邏輯運算是按位進行的,位與位之間沒有進位或借位.邏輯加法(OR)OR OPRD1,OPRD2 ;OPRD1<--OPRD1 OPRD2 算術加法(ADD)ADD OPRD1,OPRD2 ;O…

Webpack 入門指迷--轉載(題葉)

最近看到這個東西&#xff0c;一頭霧水。看了一些資料了解了Webpack概念&#xff0c;大體是webpack 是一個模塊綁定器&#xff0c;主要目的是在瀏覽器上綁定 JavaScript 文件。 看到題葉寫的一篇介紹&#xff0c;寫的很好&#xff0c;轉載連接http://segmentfault.com/a/119000…

非操作指令NOT

否操作指令NOT(又稱邏輯非運算)01 ;非0等于110 ;非1等于0NOT OPRD ;該指令把操作數OPRD取反然后送回OPRDmov ah,11111111B ;FFHnot ah ;執行后AH0Hmov ah,11110000B ;F0Hnot ah ;執行后AH00001111B 0FH

jquery的動畫學習--jquery權威指南

前面的fadeIn和fadeOut還有fadeTo以及sildeToggle還有sildeUp\sildeDown還有toggle還有show、hide等都經常用&#xff0c;就不再手寫了&#xff0c;需要注意的是fadeTo的合理應用&#xff0c;可以規定opactiy的具體數值&#xff0c;另外各個效果的回調函數可以多用用。$("…

防止Button按鈕重復點擊

背景&#xff1a;在測試中&#xff0c;測試MM總喜歡連續重復點擊Button&#xff0c;如果click事件的處理業務&#xff0c;稍微有些耗時&#xff0c;或者設備反應比較慢時&#xff0c;就會響應2遍處理&#xff0c;導致錯誤的現象出現。 前提&#xff1a;click事件的處理業務&…

8086交換指令XCHG

XCHG OPRD1,OPRD2;實現OPRD1與OPRD2之間數據交換;OPRD1,OPRD2同時是字節或字操作數, MOV AX,1 MOV BX,2 XCHG AX,BX ;執行后AX2,BX1

[傅里葉變換及其應用學習筆記] 二十四. 級聯,脈沖響應

我們上節課學習了 在離散有限維空間中&#xff0c;任何線性系統都是通過矩陣間的相乘得到的在連續無限維空間中&#xff0c;任何線性系統都是通過對核函數的積分得到的脈沖響應&#xff08;impulse response&#xff09; 級聯線性系統&#xff08;Cascading linear system&…

WPF如何實現TreeView節點重命名

我們經常看到一些軟件比如酷狗音樂&#xff0c;在對列表右鍵進行重命名的時候&#xff0c;當前列表會泛白并且進入可編輯狀態&#xff0c;當我們更改完成后就會并進入非編輯狀態&#xff0c;這些具體是怎么實現的呢&#xff1f;下面的方法也許會提供一些思路&#xff0c;下面的…

8086地址傳送指令LEA

LEA REG,OPRD ;操作數OPRD必須是一個存儲器操作數 LEA AX,IDATA ;把IDATA的偏移地址傳送到AX寄存器中DATA SEGMENTIDATA DW 1,2,3,4 DATA ENDS CODE SEGEMNT BEG:MOV AX,OFFSET IDATA ;AXIDATA的偏移地址LEA AX,IDATA ;AXIDATA的偏移地址LEA AX,DS:[IDATA] ;把ds:[IDA…

Shell --- 批量修改文件后綴腳本

for f in *.$1; dofilenamebasename $fmv $f "${filename%.*}".$2; done; Usage:&#xff1a; rename suffix rename_suffix eg: rename dat txt > ls > a.dat > rename dat txt > ls > a.txt 轉載于:https://www.cnblogs.com/RookieCoder/p/5140265.…

8086標志操作指令

標號傳送指令LAHF 把FLAG低八位送入AH。不影響FLAG的任何位LAHF ;把CF,PF,AF,ZF,SF送入AH的相應位即0,2,4,6,7位SAHF 把AH送入FLAG低八位。根據AH中的內容FLAG的低八位受到影響,高位不受影響MOV AH,11111111B SAHF ;(執行后CF,PF,AF,ZF,SF等于1)PUSHF 把FLAG壓入棧中。不影…