0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

java虛擬機(jī)與計(jì)算機(jī)內(nèi)存是如何協(xié)同工作的

冬至子 ? 來(lái)源:并發(fā)編程之美 ? 作者:妙啊 ? 2023-06-09 15:58 ? 次閱讀

介紹

為了屏蔽各種硬件操作系統(tǒng)的內(nèi)存訪問差異,以實(shí)現(xiàn)讓java程序在各種平臺(tái)下都能達(dá)到一致的并發(fā)效果,java虛擬機(jī)規(guī)范中定義了java內(nèi)存模型,簡(jiǎn)稱JMM。java內(nèi)存模型規(guī)范了java虛擬機(jī)與計(jì)算機(jī)內(nèi)存是如何協(xié)同工作的,它規(guī)定了一個(gè)線程如何和何時(shí)可以看到其他線程修改過(guò)的共享變量的值,以及在必須時(shí)如何同步地訪問共享變量。

一、jvm內(nèi)存分配結(jié)構(gòu)

圖片

  • java中的堆是運(yùn)行時(shí)的數(shù)據(jù)區(qū)域,堆的優(yōu)勢(shì)是可以動(dòng)態(tài)的分配內(nèi)存大小,生存期也不必事先告訴編譯器,垃圾回收機(jī)制負(fù)責(zé)回收不再使用的數(shù)據(jù),缺點(diǎn)是由于運(yùn)行時(shí)動(dòng)態(tài)分配內(nèi)存,因此存取速度相對(duì)慢一些。
  • 棧的優(yōu)勢(shì)是存取數(shù)據(jù)比堆要快一些,僅次于計(jì)算中的寄存器,棧的數(shù)據(jù)是可以共享的。缺點(diǎn)是存在棧中的數(shù)據(jù)的生存期以及大小必須是確定的,缺乏一些靈活性。棧中主要存放一些基本類型的變量。
  • java內(nèi)存模型要求調(diào)用棧和本地變量存放在線程棧上,對(duì)象存放在堆上。具體說(shuō)下,一個(gè)本地變量,也有可能指向一個(gè)對(duì)象的引用,這種情況下,引用這個(gè)本地變量是存放在線程棧上,但是對(duì)象本身是存放在堆上的。一個(gè)對(duì)象包含方法,方法中的本地變量是存放在線程棧上的,即使這些方法所屬的對(duì)象存放在堆上。一個(gè)對(duì)象的成員變量可能隨著對(duì)象自身存放在堆上,不管這個(gè)成員變量是原始類型還是引用類型。靜態(tài)成員變量跟隨著類的定義一起存放在堆上,存在堆上的對(duì)象可以被所持有這個(gè)對(duì)象引用的線程訪問。
  • 當(dāng)一個(gè)線程可以訪問這個(gè)對(duì)象的時(shí)候,它也可以訪問這個(gè)對(duì)象的成員變量。如果兩個(gè)線程同時(shí)調(diào)用同一個(gè)對(duì)象上的同一個(gè)方法,他們就會(huì)都訪問這個(gè)對(duì)象的成員變量,但是每一個(gè)線程都擁有了這個(gè)成員變量的私有拷貝

二、多核并發(fā)緩存架構(gòu)

圖片

  • 計(jì)算機(jī)在寄存器上執(zhí)行的速度是遠(yuǎn)大于在主內(nèi)存上執(zhí)行的速度;

  • 由于計(jì)算機(jī)的存儲(chǔ)設(shè)備與處理器的運(yùn)算速度之間存在幾個(gè)數(shù)量級(jí)的差距,所以新的計(jì)算機(jī)系統(tǒng)都不得不加入一層讀寫速度都盡可能接近處理器運(yùn)算速度的高級(jí)緩存來(lái)作為內(nèi)存與處理器之間的緩沖,將運(yùn)算使用到的數(shù)據(jù)復(fù)制到緩存中,讓運(yùn)算快速執(zhí)行,當(dāng)運(yùn)算結(jié)束后,再將數(shù)據(jù)從緩存同步到內(nèi)存中,這樣處理器就無(wú)需等待緩慢的內(nèi)存讀寫了。

  • 一個(gè)計(jì)算機(jī)還包含一個(gè)主存,所有的cpu都可以訪問這個(gè)主存,主存通常比CPU中的緩存大得多。

  • 多核cpu運(yùn)作原理:

    通常情況下,當(dāng)一個(gè)CPU需要讀取主存的時(shí)候,它會(huì)將主存的數(shù)據(jù)讀取到CPU緩存中,甚至?xí)⒕彺嬷械牟糠謨?nèi)容讀到它內(nèi)部的寄存器里面,然后在寄存器中執(zhí)行操作;當(dāng)CPU需要將結(jié)果回寫到主存的時(shí)候,它會(huì)將內(nèi)部寄存器的值刷新到緩存中,然后在某個(gè)時(shí)間點(diǎn)將值刷新回主存。

jvm內(nèi)存分配結(jié)構(gòu)與cpu多核并發(fā)緩存架構(gòu)直接的關(guān)聯(lián)

圖片

  • 硬件架構(gòu)沒有區(qū)分線程棧和堆,對(duì)于硬件架構(gòu)來(lái)說(shuō)所有的線程棧和堆都分布在主內(nèi)存中,部分的線程棧和堆可能有時(shí)候會(huì)出現(xiàn)在CPU緩存中,和CPU內(nèi)部的寄存器里面

三、java內(nèi)存模型

圖片

  • 線程之間共享變量存儲(chǔ)在主內(nèi)存中,每一個(gè)線程都有一個(gè)私有的本地內(nèi)存(工作內(nèi)存),本地內(nèi)存是java內(nèi)存模型的一個(gè)抽象的概念,不是真實(shí)存在的,它涵蓋了緩存,寫緩沖區(qū),寄存器,以及其他的硬件和編譯器的優(yōu)化。本地內(nèi)存中它存儲(chǔ)了該線程以讀或?qū)懝蚕碜兞康目截惖囊粋€(gè)副本。
  • 從更低的角度說(shuō),主內(nèi)存就是硬件的內(nèi)存,是為了獲取更好的運(yùn)行速度,虛擬機(jī)以及硬件系統(tǒng)可能會(huì)讓工作內(nèi)存優(yōu)先存儲(chǔ)于寄存器和高速緩存中。
  • java內(nèi)存模型中線程的工作內(nèi)存是CPU的寄存器和高速緩存的一個(gè)抽象的描述,而JVM的靜態(tài)內(nèi)存存儲(chǔ)模型(jvm內(nèi)存模型),它只是一種對(duì)內(nèi)存的物理化分而已,它只局限在JVM的內(nèi)存。
  • 線程A和線程B通信必須要經(jīng)過(guò)下面兩個(gè)步驟:
    • 線程A需要將本地內(nèi)存A中更新過(guò)的共享變量刷新到主內(nèi)存里面;
    • 線程B去主內(nèi)存中讀取線程A之前更新過(guò)的共享變量
  • Java的多線程之間是通過(guò)共享內(nèi)存進(jìn)行通信的,而由于采用共享內(nèi)存進(jìn)行通信,在通信過(guò)程中會(huì)存在一系列如可見性、原子性、順序性等問題,而JMM就是圍繞著多線程通信以及與其相關(guān)的一系列特性而建立的模型。JMM定義了一些語(yǔ)法集,這些語(yǔ)法集映射到Java語(yǔ)言中就是volatile、synchronized等關(guān)鍵字。

四、java內(nèi)存模型同步的八種指令操作

圖片

  • lock(鎖定):作用于主內(nèi)存的變量,把一個(gè)變量標(biāo)識(shí)為一條線程獨(dú)占狀態(tài)。
  • unlock(解鎖):作用于主內(nèi)存的變量,把一個(gè)處于鎖定狀態(tài)的變量釋放出來(lái),釋放后的變量才可以被其他線程鎖定。
  • read(讀取):作用于主內(nèi)存的變量,把一個(gè)變量值從主內(nèi)存?zhèn)鬏數(shù)骄€程的工作內(nèi)存中,以便隨后的load動(dòng)作使用。
  • load(載入):作用于工作內(nèi)存的變量,它把read操作從主內(nèi)存中得到的變量值放入工作內(nèi)存的變量副本中。
  • use(使用):作用于工作內(nèi)存的變量,把工作內(nèi)存中的一個(gè)變量傳遞給執(zhí)行引擎。每當(dāng)虛擬機(jī)遇到一個(gè)需要使用到的變量的值得字節(jié)碼指令時(shí),就會(huì)執(zhí)行這個(gè)操作。
  • assign(賦值):作用于工作內(nèi)存的變量,它把一個(gè)從執(zhí)行引擎接收到的值賦值給工作內(nèi)存的變量。每當(dāng)虛擬機(jī)遇到一個(gè)給變量賦值的字節(jié)碼指令時(shí)會(huì)執(zhí)行這個(gè)操作。
  • store(存儲(chǔ)):作用于工作內(nèi)存的變量,把工作內(nèi)存中的一個(gè)變量值傳送的主內(nèi)存中,以便隨后的write的操作
  • write(寫入):作用于主內(nèi)存的變量,它把store操作從工作內(nèi)存中一個(gè)變量的值傳送到主內(nèi)存的變量中。

對(duì)應(yīng)的java內(nèi)存模型的同步規(guī)則:

  • 如果要把一個(gè)變量從主內(nèi)存中復(fù)制到工作內(nèi)存,就需要按順序地執(zhí)行read和load操作,如果把變量從工作內(nèi)存中同步回主內(nèi)存中,就要順序地執(zhí)行store和write操作。但java內(nèi)存模型只要求上述操作必須順序執(zhí)行,而沒有保證必須是連續(xù)執(zhí)行。
  • 不允許read和load、store和write操作之一單獨(dú)出現(xiàn)。
  • 不允許一個(gè)線程丟棄它的最近assign的操作,即變量在工作內(nèi)存中改變了之后必須同步到主內(nèi)存中。
  • 不允許一個(gè)線程無(wú)原因地(沒有發(fā)生過(guò)任何assign操作)把數(shù)據(jù)從工作內(nèi)存同步回主內(nèi)存中。
  • 一個(gè)新的變量只能在主內(nèi)存中誕生,不允許在工作內(nèi)存中直接使用一個(gè)未被初始化(load或assign)的變量。即就是對(duì)一個(gè)變量實(shí)施use和store操作之前,必須先執(zhí)行過(guò)了assign和load操作。
  • 一個(gè)變量在同一時(shí)刻只允許一條線程對(duì)其進(jìn)行l(wèi)ock操作,但lock操作可以被同一條線程重復(fù)執(zhí)行多次,多次執(zhí)行l(wèi)ock后,只有執(zhí)行相同次數(shù)的unlock操作,變量才會(huì)被解鎖。lock和unlock必須成對(duì)出現(xiàn)。
  • 如果對(duì)一個(gè)變量執(zhí)行l(wèi)ock操作,將會(huì)清空工作內(nèi)存中次變量的值,在執(zhí)行引擎使用這個(gè)變量前需要重新執(zhí)行l(wèi)oad或assign操作初始化變量的值。
  • 如果一個(gè)變量事先沒有被lock操作鎖定,則不允許對(duì)他執(zhí)行unlock操作;也不允許去unlock一個(gè)被其他線程鎖定的變量。
  • 對(duì)一個(gè)變量執(zhí)行unlock操作之前,必須先把此變量同步到主內(nèi)存中(執(zhí)行store和write操作)。

五、案列分析

下面我們結(jié)合java內(nèi)存模型分析下共享變量執(zhí)行i++的操作流程:

圖片

  • 初始化共享變量i=0。
  • 線程1通過(guò)read指令從主內(nèi)存中讀取出共享變量i=0,通過(guò)load指令加載到線程1的工作內(nèi)存中。
  • 在線程1的工作內(nèi)存中,通過(guò)use指令將共享變量i=0加載到cpu執(zhí)行引擎進(jìn)行+1計(jì)算,計(jì)算后共享變量i=1。
  • 在線程1的工作內(nèi)存中,通過(guò)assign指令將cpu執(zhí)行引擎計(jì)算后的共享變量i=1賦值到線程1的工作內(nèi)存中。
  • 線程1通過(guò)store指令將線程1中工作內(nèi)存的共享變量同步到主內(nèi)存中。
  • 在線程1的主內(nèi)存中,通過(guò)write指令將共享變量i=1的值賦值給主內(nèi)存的該共享變量,從而完成一次i++操作。
  • 那么當(dāng)線程1還未將共享變量的值同步賦值回寫到主內(nèi)存時(shí),線程2開始進(jìn)行了i++操作,線程2通過(guò)read指令讀取到的共享變量i的值此時(shí)還是0,那么線程2又在0的基礎(chǔ)進(jìn)行了i++操作。所以當(dāng)很多線程并發(fā)執(zhí)行i++操作時(shí),結(jié)果是與我們預(yù)期不符的。
  • 以上結(jié)合java內(nèi)存模型分析了我們共享變量的一個(gè)執(zhí)行流程。解釋了i++操作是一個(gè)線程不安全的。

結(jié)語(yǔ)

上一篇我們分析了java并發(fā)包中cas的原理,這篇總結(jié)下cas涉及到的java內(nèi)存模型的原理,cas還涉及到的cpu緩存一致性協(xié)議,我們后面繼續(xù)分析。

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • 處理器
    +關(guān)注

    關(guān)注

    68

    文章

    19038

    瀏覽量

    228482
  • 寄存器
    +關(guān)注

    關(guān)注

    31

    文章

    5271

    瀏覽量

    119655
  • JAVA
    +關(guān)注

    關(guān)注

    19

    文章

    2946

    瀏覽量

    104372
  • 虛擬機(jī)
    +關(guān)注

    關(guān)注

    1

    文章

    897

    瀏覽量

    27969
收藏 人收藏

    評(píng)論

    相關(guān)推薦

    計(jì)算機(jī)語(yǔ)言概述

    具有可移植性、安全性,這正是Java成為網(wǎng)絡(luò)開發(fā)的主流語(yǔ)言的原因。JVM(Java Virtual Machine)是一種Java虛擬機(jī),從結(jié)構(gòu)上看它與實(shí)際的
    發(fā)表于 12-06 00:17

    Java虛擬機(jī)介紹

    什么是JVM?Java虛擬機(jī)Java Virtual Machine, JVM)實(shí)際上是一個(gè)類似于真實(shí)計(jì)算機(jī)系統(tǒng)的抽象機(jī)(Abstract
    發(fā)表于 04-10 16:15 ?0次下載

    微軟java虛擬機(jī)下載

    微軟java虛擬機(jī)下載:Java虛擬機(jī)(JVM)是Java Virtual Machine的縮寫,它是一個(gè)虛構(gòu)出來(lái)的
    發(fā)表于 02-26 08:26 ?38次下載

    計(jì)算機(jī)內(nèi)部總線,計(jì)算機(jī)內(nèi)部總線是什么意思

    計(jì)算機(jī)內(nèi)部總線,計(jì)算機(jī)內(nèi)部總線是什么意思    由于計(jì)算機(jī)內(nèi)部的主要工作過(guò)程是信息傳送和加工的過(guò)程,因此在機(jī)器內(nèi)部各部件之間的數(shù)據(jù)傳送非常頻繁。為了
    發(fā)表于 04-13 10:31 ?7357次閱讀

    Java虛擬機(jī)基礎(chǔ)

    JVM基礎(chǔ)----java虛擬機(jī)的學(xué)習(xí)內(nèi)容。
    發(fā)表于 10-30 10:21 ?0次下載

    深入JAVA虛擬機(jī)

    深入JAVA虛擬機(jī)
    發(fā)表于 03-19 11:24 ?1次下載

    分析java虛擬機(jī)內(nèi)存要如何分配

    概述 Java虛擬機(jī)在執(zhí)行Java程序的過(guò)程中會(huì)把它所管理的內(nèi)存劃分為若干個(gè)不同數(shù)據(jù)區(qū)域。這些區(qū)域都有各自的用途,以及創(chuàng)建和銷毀的時(shí)間,有的區(qū)域隨著
    發(fā)表于 09-27 16:43 ?0次下載

    Java內(nèi)存區(qū)域分配、Java虛擬機(jī)棧、對(duì)象的訪問方式和GC

    對(duì)于Java程序員來(lái)說(shuō),在虛擬機(jī)的自動(dòng)內(nèi)存管理機(jī)制的幫助下,不再需要為每一個(gè)new操作去寫配對(duì)的delete/free代碼,而且不容易出現(xiàn) 內(nèi)存泄漏和
    發(fā)表于 12-11 16:28 ?2261次閱讀
    <b class='flag-5'>Java</b><b class='flag-5'>內(nèi)存</b>區(qū)域分配、<b class='flag-5'>Java</b><b class='flag-5'>虛擬機(jī)</b>棧、對(duì)象的訪問方式和GC

    虛擬機(jī)內(nèi)省與內(nèi)存安全監(jiān)測(cè)

    針對(duì)在傳統(tǒng)特權(quán)虛擬機(jī)中利用虛擬機(jī)內(nèi)省實(shí)時(shí)監(jiān)測(cè)其他虛擬機(jī)內(nèi)存安全的方法不利于安全模塊與系統(tǒng)其他部分的隔離,且會(huì)拖慢虛擬平臺(tái)的整體性能的問題,提出基于輕量操作系統(tǒng)實(shí)現(xiàn)
    發(fā)表于 01-08 14:15 ?0次下載
    <b class='flag-5'>虛擬機(jī)內(nèi)</b>省與<b class='flag-5'>內(nèi)存</b>安全監(jiān)測(cè)

    私有云平臺(tái)的虛擬機(jī)內(nèi)存調(diào)度策略

    對(duì)虛擬機(jī)內(nèi)存緊缺、內(nèi)存空閑時(shí)的實(shí)時(shí)監(jiān)測(cè)和動(dòng)態(tài)調(diào)度,并且提出虛擬機(jī)遷移策略,有效地緩解宿主機(jī)的內(nèi)存緊缺問題。最后選取一臺(tái)物理機(jī)作為主控節(jié)點(diǎn),兩
    發(fā)表于 01-29 16:52 ?0次下載
    私有云平臺(tái)的<b class='flag-5'>虛擬機(jī)內(nèi)存</b>調(diào)度策略

    計(jì)算平臺(tái)中多虛擬機(jī)內(nèi)存協(xié)同優(yōu)化策略研究

    虛擬化技術(shù)為云計(jì)算基礎(chǔ)設(shè)施資源的動(dòng)態(tài)部署、安全隔離提供了重要保證.從過(guò)度占用內(nèi)存虛擬機(jī)中回收內(nèi)存,提供給
    發(fā)表于 03-27 18:18 ?15次下載
    云<b class='flag-5'>計(jì)算</b>平臺(tái)中多<b class='flag-5'>虛擬機(jī)內(nèi)存</b><b class='flag-5'>協(xié)同</b>優(yōu)化策略研究

    如何去優(yōu)化計(jì)算機(jī)內(nèi)存

    大多數(shù)計(jì)算和存儲(chǔ)部署如今面臨的情況是,計(jì)算機(jī)內(nèi)存空間都受到了上限的限制。
    發(fā)表于 11-28 17:48 ?1146次閱讀
    如何去優(yōu)化<b class='flag-5'>計(jì)算機(jī)內(nèi)存</b>

    由淺入深的了解Java虛擬機(jī)

    說(shuō)到Java虛擬機(jī),相信作為Java程序員的小伙伴們都不陌生,他們每天都在寫Java代碼,寫的代碼都是在一個(gè)叫做Java
    的頭像 發(fā)表于 01-01 17:50 ?2265次閱讀

    java虛擬機(jī)內(nèi)存包括遠(yuǎn)空間內(nèi)存

    Java虛擬機(jī)(JVM)內(nèi)存Java程序執(zhí)行時(shí)所使用的內(nèi)存空間的總稱,包括了Java堆、方法區(qū)
    的頭像 發(fā)表于 12-05 14:15 ?347次閱讀

    計(jì)算機(jī)主機(jī)內(nèi)部結(jié)構(gòu)

    計(jì)算機(jī)主機(jī)的內(nèi)部結(jié)構(gòu)是一個(gè)復(fù)雜而精密的系統(tǒng),它包含了多個(gè)關(guān)鍵組件,這些組件協(xié)同工作以實(shí)現(xiàn)計(jì)算機(jī)的各種功能。以下是對(duì)計(jì)算機(jī)主機(jī)內(nèi)部結(jié)構(gòu)的詳細(xì)解析。
    的頭像 發(fā)表于 09-26 16:40 ?338次閱讀