最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Java編程偽共享與緩存行填充

 更新時(shí)間:2021年09月28日 08:46:41   作者:行云創(chuàng)新  
這篇文章主要介紹了Java編程偽共享與緩存行填充,下面文章Disruptor提到的CPU緩存話題,做了一些嘗試和研究,如Disruptor所說(shuō),CPU有緩存?zhèn)喂蚕淼膯?wèn)題,并且通過(guò)緩存行填充能完美的解決這個(gè)問(wèn)題,需要的朋友可以參考一下

最近在回顧Disruptor的相關(guān)知識(shí),覺(jué)得Disruptor在計(jì)算機(jī)底層的領(lǐng)域確實(shí)比一般人厲害不少,以前在寫(xiě)程序的時(shí)候,基本是從應(yīng)用邏輯的角度考慮,覺(jué)得設(shè)計(jì)模式+少量算法+ 優(yōu)美的代碼=理想的結(jié)果,但看完Disruptor的設(shè)計(jì)后,覺(jué)得只考慮應(yīng)用本身是有一定的局限性,還需要懂底層,硬件層面的東西,就像Disruptor一樣,通過(guò)底層優(yōu)化,讓程序有質(zhì)的飛躍。

下面就Disruptor提到的CPU緩存話題,做了一些嘗試和研究,如Disruptor所說(shuō),CPU有緩存?zhèn)喂蚕淼膯?wèn)題,并且通過(guò)緩存行填充能完美的解決這個(gè)問(wèn)題。

1、CPU緩存

CPU是機(jī)器的心臟,最終由它來(lái)執(zhí)行所有運(yùn)算和程序。主內(nèi)存(RAM)是存放數(shù)據(jù)(包括代碼行)的地方。CPU和主內(nèi)存之間有好幾層緩存,即使直接訪問(wèn)主內(nèi)存也是非常慢的。如果你正在多次對(duì)一塊數(shù)據(jù)做相同的運(yùn)算,那么在執(zhí)行運(yùn)算的時(shí)候把它加載到離CPU很近的地方就有意義了(比如一個(gè)循環(huán)計(jì)數(shù))。下面是CPU的緩存結(jié)構(gòu)圖:

越靠近CPU的核緩存越快但是也越小,所以一級(jí)緩存很小但很快,并且緊靠著在使用它的CPU內(nèi)核。二級(jí)緩存大一些,也慢一些,注意一級(jí)二級(jí)緩存只能被一個(gè)單獨(dú)的CPU的單個(gè)核使用。三級(jí)緩存在現(xiàn)代多核機(jī)器中更普遍,仍然更大,更慢,但是被單個(gè)插槽上的所有CPU核共享。最后,你擁有一塊主存,由全部插槽上的所有CPU核共享。當(dāng)CPU執(zhí)行運(yùn)算的時(shí)候,它先去一級(jí)緩存查找所需的數(shù)據(jù),再去二級(jí)緩存,然后是三級(jí)緩存,最后如果這些緩存中都沒(méi)有,所需的數(shù)據(jù)就要去主內(nèi)存拿。走得越遠(yuǎn),運(yùn)算耗費(fèi)的時(shí)間就越長(zhǎng)。所以如果你在做一些很頻繁的事,你要確保數(shù)據(jù)在一級(jí)緩存中。

這是在網(wǎng)上找到的一份CPU緩存未命中時(shí)候的CPU時(shí)鐘消耗一級(jí)大概的耗時(shí):

2、CPU緩存行與偽共享

數(shù)據(jù)在緩存中不是以獨(dú)立的項(xiàng)來(lái)存儲(chǔ),不是單獨(dú)的變量,也不是單獨(dú)的指針。緩存系統(tǒng)中是以緩存行(cache line)為單位存儲(chǔ),緩存行是2的整數(shù)冪個(gè)連續(xù)字節(jié),一般為32-256個(gè)字節(jié),最常見(jiàn)的緩存行大小是64個(gè)字節(jié)。

下面是CPU緩存行的邏輯圖:

CPU從主內(nèi)存中加載數(shù)據(jù)的時(shí)候,不是只加載某一個(gè)變量的值,而是加載一個(gè)緩存行的值,例如一個(gè)Java的long類(lèi)型是8字節(jié),因此在一個(gè)緩存行中可以存8個(gè)long類(lèi)型的變量。如果你訪問(wèn)一個(gè)long類(lèi)型的數(shù)組,當(dāng)數(shù)組中的一個(gè)值被加載到緩存中,它會(huì)額外加載另外7個(gè)。如果你數(shù)據(jù)結(jié)構(gòu)中的項(xiàng)在內(nèi)存中不是彼此相鄰的,例如鏈表LinkedList結(jié)構(gòu),你將得不到緩存行加載所帶來(lái)的優(yōu)勢(shì),并且在這些數(shù)據(jù)結(jié)構(gòu)中的每一個(gè)項(xiàng)都可能會(huì)出現(xiàn)緩存未命中,這是也是鏈表不適合遍歷的原因之一。

但是,緩存行加載某一塊內(nèi)存數(shù)據(jù),這個(gè)有好處也有壞處,緩存行不是單個(gè)數(shù)據(jù),而是一組數(shù)據(jù),如上圖所示當(dāng)2個(gè)線程同時(shí)運(yùn)行在2個(gè)core上,同時(shí)加載了同一個(gè)緩存行,Core1修改X數(shù)據(jù),Core2讀Y數(shù)據(jù),Core1修改后提交,Core2發(fā)現(xiàn)X數(shù)據(jù)有變化,緩存未命中,就會(huì)重新加載整個(gè)緩存行,但是Core2并不會(huì)用X數(shù)據(jù),而是讀Y數(shù)據(jù),去重新加載整個(gè)緩存行的數(shù)據(jù),無(wú)意中影響彼此的性能。如果兩個(gè)獨(dú)立的線程同時(shí)寫(xiě)兩個(gè)不同的值會(huì)更糟,因?yàn)槊看尉€程對(duì)緩存行進(jìn)行寫(xiě)操作時(shí),每個(gè)內(nèi)核都要把另一個(gè)內(nèi)核上的緩存塊無(wú)效掉并重新讀取里面的數(shù)據(jù)。你基本上是遇到兩個(gè)線程之間的寫(xiě)沖突了,盡管它們寫(xiě)入的是不同的變量。每個(gè)線程都要去競(jìng)爭(zhēng)緩存行的所有權(quán)來(lái)更新變量。如果核心1獲得了所有權(quán),緩存子系統(tǒng)將會(huì)使核心2中對(duì)應(yīng)的緩存行失效。當(dāng)核心2獲得了所有權(quán)然后執(zhí)行更新操作,核心1就要使自己對(duì)應(yīng)的緩存行失效。這會(huì)來(lái)來(lái)回回的經(jīng)過(guò)CPU三級(jí)緩存,大大影響了性能。如果互相競(jìng)爭(zhēng)的核心位于不同的插槽,就要額外橫跨插槽連接,問(wèn)題可能更加嚴(yán)重,這就是CPU緩存?zhèn)喂蚕怼?/p>

3、Java處理緩存?zhèn)喂蚕?/h2>

緩存行填充:

因?yàn)槭怯布讓拥倪壿嫞瑤缀跛谐绦蛟谂艿臅r(shí)候都會(huì)遇到這個(gè)問(wèn)題,那么java是如何處理這個(gè)問(wèn)題呢?答案就是 緩存行填充

對(duì)于HotSpot JVM,所有對(duì)象都有兩個(gè)字長(zhǎng)的對(duì)象頭。第一個(gè)字是由24位哈希碼和8位標(biāo)志位(如鎖的狀態(tài)或作為鎖對(duì)象)組成的Mark Word。第二個(gè)字是對(duì)象所屬類(lèi)的引用。如果是數(shù)組對(duì)象還需要一個(gè)額外的字來(lái)存儲(chǔ)數(shù)組的長(zhǎng)度。每個(gè)對(duì)象的起始地址都對(duì)齊于8字節(jié)以提高性能。因此當(dāng)封裝對(duì)象的時(shí)候?yàn)榱烁咝剩瑢?duì)象字段聲明的順序會(huì)被重排序成下列基于字節(jié)大小的順序:

doubles (8) 和 longs (8)
ints (4) 和 floats (4)
shorts (2) 和 chars (2)
booleans (1) 和 bytes (1)
references (4/8)
<子類(lèi)字段重復(fù)上述順序>


通過(guò)對(duì)熱點(diǎn)變量周?chē)M(jìn)行緩存行填充,來(lái)規(guī)避緩存?zhèn)喂蚕韼?lái)的問(wèn)題,對(duì)于緩存行大小是64字節(jié)或更少的處理器架構(gòu)來(lái)說(shuō)是這樣的,有可能處理器的緩存行是128字節(jié),那么使用64字節(jié)填充還是會(huì)存在偽共享問(wèn)題,通過(guò)增加補(bǔ)全變量的個(gè)數(shù)來(lái)確保熱點(diǎn)變量不會(huì)和其他東西同時(shí)存在于一個(gè)緩存行中。下面是Disruptor對(duì)ring buffer的序列號(hào)做的補(bǔ)全代碼:

public long p1, p2, p3, p4, p5, p6, p7; // cache line padding
private volatile long cursor = INITIAL_CURSOR_VALUE; 
public long p8, p9, p10, p11, p12, p13, p14; // cache line padding


當(dāng)CPU緩存加載cursor變量的時(shí)候,會(huì)連帶加載周邊的7個(gè)long類(lèi)型變量,但是這幾個(gè)long類(lèi)型變量不會(huì)有任何線程去修改它,因此不會(huì)出現(xiàn)緩存未命中問(wèn)題,完美規(guī)避了緩存?zhèn)喂蚕淼膯?wèn)題。

4、Java程序代碼驗(yàn)證

官方也給了一個(gè)java的測(cè)試demo,那么下面針對(duì)各種不同的情景,做一下實(shí)驗(yàn)看看,是不是有緩存?zhèn)喂蚕磉@個(gè)問(wèn)題,測(cè)試代碼如下:

下面針對(duì)各個(gè)測(cè)試場(chǎng)景,做一下簡(jiǎn)單的描述:

場(chǎng)景一:對(duì)Long變量進(jìn)行寫(xiě)入,沒(méi)有緩存行填充,沒(méi)有volatile關(guān)鍵字。

場(chǎng)景二:對(duì)Long變量進(jìn)行寫(xiě)入,有緩存行填充,沒(méi)有volatile關(guān)鍵字。

場(chǎng)景三:對(duì)Long變量進(jìn)行寫(xiě)入,沒(méi)有緩存行填充,有volatile關(guān)鍵字。

場(chǎng)景四:對(duì)Long變量進(jìn)行寫(xiě)入,有緩存行填充,有volatile關(guān)鍵字。

下面是針對(duì)各個(gè)場(chǎng)景的測(cè)試結(jié)果(每個(gè)場(chǎng)景測(cè)試3次,取平均值):

從測(cè)試結(jié)果來(lái)看,場(chǎng)景一和場(chǎng)景二差不多,有緩存行填充的稍微快那么一點(diǎn)點(diǎn),區(qū)別不大,都是192276000納秒左右。場(chǎng)景三和場(chǎng)景四有volatile關(guān)鍵字的就不一樣了,這里可以看出volatile關(guān)鍵字對(duì)一個(gè)變量的讀取和寫(xiě)入性能影響還是比較大,寫(xiě)入耗時(shí)是直接寫(xiě)入的200多倍,因此volatile關(guān)鍵字怎么用很關(guān)鍵,用到哪些地方也很關(guān)鍵,不要在代碼里面隨便加,不會(huì)用反而會(huì)影響程序運(yùn)行效率。場(chǎng)景三有volatile關(guān)鍵字,但是沒(méi)有進(jìn)行緩存行填充,耗時(shí)是有緩存行填充的10幾倍,這里就能看出緩存行填充的效果在用到了內(nèi)存屏障的時(shí)候還是很明顯。

CPU緩存?zhèn)喂蚕淼膯?wèn)題,確實(shí)打破了很多人對(duì)常規(guī)程序執(zhí)行的理解,如何才能應(yīng)用到工作中呢?有以下幾點(diǎn)需要注意:

  • 對(duì)volatile很熟悉,并且代碼里面使用到了緩存屏障,需要看看能否用到這個(gè)緩存填充行。
  • 清楚程序在某個(gè)時(shí)刻會(huì)有緩存?zhèn)喂蚕韱?wèn)題,例如某幾個(gè)代碼在一起的變量會(huì)被多個(gè)線程同時(shí)使用并且有寫(xiě)入操作,需要用緩存填充行把這幾個(gè)變量隔開(kāi)。
  • 能使用工具分析自己寫(xiě)的程序,看看有緩存填充行過(guò)后,是否真的能提升效率,例如JProfiler分析工具。

到此這篇關(guān)于Java編程偽共享與緩存行填充的文章就介紹到這了,更多相關(guān)Java編程偽共享與緩存行填充內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • spring jpa ManyToMany原理及用法詳解

    spring jpa ManyToMany原理及用法詳解

    這篇文章主要介紹了spring jpa ManyToMany原理及用法詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2019-10-10
  • 如何基于java實(shí)現(xiàn)Gauss消元法過(guò)程解析

    如何基于java實(shí)現(xiàn)Gauss消元法過(guò)程解析

    這篇文章主要介紹了如何基于java實(shí)現(xiàn)Gauss消元法過(guò)程解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-10-10
  • 基于CXF搭建webService的實(shí)例講解

    基于CXF搭建webService的實(shí)例講解

    下面小編就為大家?guī)?lái)一篇基于CXF搭建webService的實(shí)例講解。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2017-11-11
  • springboot RESTful以及參數(shù)注解的使用方式

    springboot RESTful以及參數(shù)注解的使用方式

    這篇文章主要介紹了springboot RESTful以及參數(shù)注解的使用方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-10-10
  • Netty分布式高性能工具類(lèi)同線程下回收對(duì)象解析

    Netty分布式高性能工具類(lèi)同線程下回收對(duì)象解析

    這篇文章主要為大家介紹了Netty分布式高性能工具類(lèi)同線程下回收對(duì)象解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-03-03
  • JAVA基于SnakeYAML實(shí)現(xiàn)解析與序列化YAML

    JAVA基于SnakeYAML實(shí)現(xiàn)解析與序列化YAML

    這篇文章主要介紹了JAVA基于SnakeYAML實(shí)現(xiàn)解析與序列化YAML,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2019-12-12
  • 詳解@ConfigurationProperties實(shí)現(xiàn)原理與實(shí)戰(zhàn)

    詳解@ConfigurationProperties實(shí)現(xiàn)原理與實(shí)戰(zhàn)

    這篇文章主要介紹了詳解@ConfigurationProperties實(shí)現(xiàn)原理與實(shí)戰(zhàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-10-10
  • springboot實(shí)現(xiàn)分頁(yè)功能的完整代碼

    springboot實(shí)現(xiàn)分頁(yè)功能的完整代碼

    Spring Boot是一個(gè)快速開(kāi)發(fā)框架,它提供了很多便捷的功能,其中包括分頁(yè)查詢(xún),下面這篇文章主要給大家介紹了關(guān)于springboot實(shí)現(xiàn)分頁(yè)功能的相關(guān)資料,文中通過(guò)實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2023-04-04
  • JAVA記住密碼功能的實(shí)現(xiàn)代碼

    JAVA記住密碼功能的實(shí)現(xiàn)代碼

    這篇文章主要介紹了JAVA記住密碼功能的實(shí)現(xiàn)代碼,代碼簡(jiǎn)單易懂,非常不錯(cuò),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-01-01
  • 更改idea的JDK版本超簡(jiǎn)單便捷方法

    更改idea的JDK版本超簡(jiǎn)單便捷方法

    idea很多地方都設(shè)置了jdk版本,不同模塊的jdk版本也可能不一樣,下面這篇文章主要給大家介紹了關(guān)于更改idea的JDK版本的超簡(jiǎn)單便捷方法,文中通過(guò)圖文介紹的非常詳細(xì),需要的朋友可以參考下
    2023-11-11

最新評(píng)論

湖南省| 盐亭县| 南雄市| 岚皋县| 合川市| 安多县| 双峰县| 辛集市| 天水市| 星座| 勃利县| 奉化市| 囊谦县| 岑巩县| 抚顺市| 闽侯县| 土默特右旗| 古浪县| 通江县| 石林| 彩票| 邹平县| 保靖县| 内乡县| 乌恰县| 陇西县| 雅安市| 浑源县| 察哈| 时尚| 安达市| 清远市| 崇信县| 瑞安市| 乳山市| 禹州市| 河北省| 顺平县| 天峨县| 陈巴尔虎旗| 大洼县|