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

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

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

Java運(yùn)行時(shí)內(nèi)存區(qū)域與硬件內(nèi)存的關(guān)系1

jf_78858299 ? 來源:小牛呼嚕嚕 ? 作者:小牛呼嚕嚕 ? 2023-02-09 14:41 ? 次閱讀

什么是 JMM?

在上一篇文章中,我們了解了計(jì)算機(jī)由于各個(gè)硬件的讀取速度之間的巨大差距,和充分利用CPU的性能的手段方法,及其所帶來的一系列問題:

  1. 為了充分壓榨CPU的性能, CPU 會(huì)對(duì)指令亂序執(zhí)行或者語言的編譯器會(huì)指令重排 ,讓CPU一直工作不停歇,但同時(shí)會(huì)導(dǎo)致有序性問題。
  2. 為了平衡CPU的寄存器和內(nèi)存的速度差異,計(jì)算機(jī)的CPU 增加了高速緩存,但同時(shí)導(dǎo)致了 可見性問題
  3. 為了平衡CPU 與 I/O 設(shè)備的速度差異,操作系統(tǒng)增加了進(jìn)程、線程概念,以分時(shí)復(fù)用 CPU,但同時(shí)導(dǎo)致了原子性問題。

Java 是最早嘗試提供內(nèi)存模型的編程語言。由于Java 語言是跨平臺(tái)的,另外各個(gè)操作系統(tǒng)總存在一些差異,Java在物理機(jī)器的基礎(chǔ)上抽象出一個(gè)內(nèi)存模型(JMM)

JMM 可以看作是 Java 定義的并發(fā)編程相關(guān)的一組規(guī)范,除了抽象了線程和主內(nèi)存之間的關(guān)系之外,其還規(guī)定了從 Java 源代碼到 CPU 可執(zhí)行指令的這個(gè)轉(zhuǎn)化過程要遵守哪些和并發(fā)相關(guān)的原則和規(guī)范,這樣就可以屏蔽各個(gè)操作系統(tǒng)的差異,簡(jiǎn)化多線程編程。

Java 運(yùn)行時(shí)內(nèi)存區(qū)域與硬件內(nèi)存的關(guān)系

Java 內(nèi)存區(qū)域和Java內(nèi)存模型有何區(qū)別?

這是一個(gè)非常容易讓人混淆的問題,Java 內(nèi)存區(qū)域和內(nèi)存模型完全是不一樣的東西,

  1. Java 內(nèi)存區(qū)域, 也叫內(nèi)存區(qū)域、JVM內(nèi)存模型,和 Java 虛擬機(jī)(JVM)的運(yùn)行時(shí)區(qū)域相關(guān),是指 JVM運(yùn)行時(shí)將數(shù)據(jù)分區(qū)域存儲(chǔ),強(qiáng)調(diào)對(duì)內(nèi)存空間的劃分。
  2. Java內(nèi)存模型,也叫內(nèi)存模型(JMM),是Java 定義的并發(fā)編程相關(guān)的一組規(guī)范,除了抽象了線程和主內(nèi)存之間的關(guān)系之外,其還規(guī)定了從 Java 源代碼到 CPU 可執(zhí)行指令的這個(gè)轉(zhuǎn)化過程要遵守哪些和并發(fā)相關(guān)的原則和規(guī)范,屏蔽各個(gè)操作系統(tǒng)的差異。通俗點(diǎn)說: JMM規(guī)范了程序中變量的訪問規(guī)則,保證了操作的原子性、可見性、有序性, 我們下文慢慢道來。

我們知道JVM 運(yùn)行時(shí)內(nèi)存區(qū)域是分區(qū)域的,分為棧、堆等,其實(shí)這些都是 JVM 定義的邏輯概念。但在傳統(tǒng)的硬件內(nèi)存架構(gòu)中是沒有棧和堆這種概念。

其中:

  1. 圖中??梢约?xì)分為:虛擬機(jī)棧(JVM Stacks) 本地方法棧(Native Method Stack)
  • 虛擬機(jī)棧(JVM Stacks): 線程私有,它的生命周期和線程相同 ,描述的是Java方法執(zhí)行的內(nèi)存模型,每個(gè)方法在執(zhí)行的同時(shí)都會(huì)創(chuàng)建一個(gè)線幀(Stack Frame)用于存儲(chǔ)局部變量表、操作數(shù)棧、動(dòng)態(tài)鏈接、方法出口等信息,每個(gè)方法從調(diào)用直至執(zhí)行完成的過程,都對(duì)應(yīng)著一個(gè)線幀在虛擬機(jī)棧中入棧到出棧的過程
  • 本地方法棧(Native Method Stack): 線程私有 ,本地方法棧與虛擬機(jī)棧的作用是一樣的,只不過虛擬機(jī)棧是服務(wù)Java方法的,而本地方法棧是為虛擬機(jī)調(diào)用Native方法服務(wù)的。在Java虛擬機(jī)規(guī)范中對(duì)于本地方法棧沒有特殊的要求,虛擬機(jī)可以自由的實(shí)現(xiàn)它,因此 在Sun HotSpot虛擬機(jī)直接把本地方法棧和虛擬機(jī)棧合二為一了 。線程開始調(diào)用本地方法時(shí),會(huì)進(jìn)入 不再受 JVM 約束的世界。本地方法可以通過 JNI(Java Native Interface)來訪問虛擬機(jī)運(yùn)行時(shí)的數(shù)據(jù)區(qū),甚至可以調(diào)用寄存器,具有和 JVM 相同的能力和權(quán)限。JNI 類本地方法最著名的應(yīng)該是 System.currentTimeMillis()
  1. 堆(Heap)

虛擬機(jī)堆是Java虛擬機(jī)中內(nèi)存最大的一塊,是被所有線程共享的,在虛擬機(jī)啟動(dòng)時(shí)候創(chuàng)建,Java堆唯一的目的就是存放對(duì)象實(shí)例,幾乎所有的對(duì)象實(shí)例都在這里分配內(nèi)存,隨著JIT編譯器的發(fā)展和逃逸分析技術(shù)的逐漸成熟,棧上分配、標(biāo)量替換優(yōu)化的技術(shù)將會(huì)導(dǎo)致一些微妙的變化,所有的對(duì)象都分配在堆上漸漸變得不那么“絕對(duì)”了。

Java中棧和堆既存在于計(jì)算機(jī)的高速緩存中,又存在于主存中,所以兩者并沒有很直接的關(guān)系。

Java 線程與主內(nèi)存的關(guān)系

Java 內(nèi)存模型(JMM) 抽象了線程和主內(nèi)存之間的關(guān)系,就比如說線程之間的共享變量必須存儲(chǔ)在主內(nèi)存中。在 JDK1.2 之前,Java 的內(nèi)存模型實(shí)現(xiàn)總是從 主存 (即共享內(nèi)存)讀取變量,是不需要進(jìn)行特別的注意的。而在當(dāng)前的 Java 內(nèi)存模型下,線程可以把變量保存 本地內(nèi)存 (比如機(jī)器的寄存器)中,而不是直接在主存中進(jìn)行讀寫。這就可能造成一個(gè)線程在主存中修改了一個(gè)變量的值,而另外一個(gè)線程還繼續(xù)使用它在寄存器中的變量值的拷貝,造成數(shù)據(jù)的不一致。

什么是主內(nèi)存?什么是本地內(nèi)存?

  • 主內(nèi)存 :所有線程創(chuàng)建的實(shí)例對(duì)象都存放在主內(nèi)存中,不管該實(shí)例對(duì)象是成員變量還是方法中的本地變量(也稱局部變量)
  • 本地內(nèi)存 :每個(gè)線程都有一個(gè)私有的本地內(nèi)存來存儲(chǔ)共享變量的副本,并且,每個(gè)線程只能訪問自己的本地內(nèi)存,無法訪問其他線程的本地內(nèi)存。本地內(nèi)存是 JMM 抽象出來的一個(gè)概念,存儲(chǔ)了主內(nèi)存中的共享變量副本。

Java 內(nèi)存模型其實(shí)是一種規(guī)范,定義了很多東西:

  • 所有的變量都存儲(chǔ)在主內(nèi)存(Main Memory)中。
  • 每個(gè)線程都有一個(gè)私有的本地內(nèi)存 (Local Memory),本地內(nèi)存中存儲(chǔ)了該線程以讀/寫共享變量的拷貝副本。
  • 線程對(duì)變量的所有操作都必須在本地內(nèi)存中進(jìn)行,而不能直接讀寫主內(nèi)存。
  • 不同的線程之間無法直接訪問對(duì)方本地內(nèi)存中的變量。

這里所講的主內(nèi)存、工作內(nèi)存與 Java 內(nèi)存區(qū)域中的 Java 堆、棧、方法區(qū)等并不是同一個(gè)層次的內(nèi)存劃分,這兩者基本上是沒有關(guān)系的,如果兩者一定要勉強(qiáng)對(duì)應(yīng)起來,那從變量、主內(nèi)存、工作內(nèi)存的定義來看,主內(nèi)存主要對(duì)應(yīng)于Java堆中的對(duì)象實(shí)例數(shù)據(jù)部分,而工作內(nèi)存則對(duì)應(yīng)于虛擬機(jī)棧中的部分區(qū)域。

聲明:本文內(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)投訴
  • JAVA
    +關(guān)注

    關(guān)注

    19

    文章

    2943

    瀏覽量

    104107
  • 編譯器
    +關(guān)注

    關(guān)注

    1

    文章

    1602

    瀏覽量

    48896
  • JVM
    JVM
    +關(guān)注

    關(guān)注

    0

    文章

    155

    瀏覽量

    12168
收藏 人收藏

    評(píng)論

    相關(guān)推薦

    Labview 運(yùn)行時(shí)內(nèi)存增加

    的dll,用庫函數(shù)直接調(diào)用這個(gè)dll后,Labview運(yùn)行時(shí)所占的內(nèi)存基本上保持在0.9 M左右,不會(huì)卡死了。附件里是那個(gè)網(wǎng)友上傳的dll,大家可以下載后將.jpg改為.dll
    發(fā)表于 05-19 14:38

    C6748內(nèi)存分配運(yùn)行時(shí)出錯(cuò)

    因?yàn)樾枰獙?duì)大量數(shù)據(jù)進(jìn)行處理,我設(shè)置一個(gè)指針,內(nèi)存分配1000*sizeof(float),運(yùn)行時(shí)出錯(cuò),查看其地址為0x00000000(肯定不對(duì)),如果減小分配空間,如200*sizeof
    發(fā)表于 03-16 10:05

    C語言內(nèi)存運(yùn)行時(shí)不同變量是怎樣分配的

    C語言內(nèi)存運(yùn)行時(shí)不同變量是怎樣分配的?怎樣驗(yàn)證C語言編譯后的內(nèi)存地址分配是否合理?
    發(fā)表于 02-25 06:37

    請(qǐng)問單片機(jī)運(yùn)行時(shí)內(nèi)存是如何分配的?

    請(qǐng)問單片機(jī)運(yùn)行時(shí)內(nèi)存是如何分配的? 是在鏈接腳本中人工定義?還是編譯器根據(jù)某種算法自動(dòng)分配?
    發(fā)表于 09-27 08:16

    java線程內(nèi)存模型

    一、Java內(nèi)存模型 按照官方的說法:Java 虛擬機(jī)具有一個(gè)堆,堆是運(yùn)行時(shí)數(shù)據(jù)區(qū)域,所有類實(shí)例和數(shù)組的
    發(fā)表于 09-27 10:55 ?0次下載
    <b class='flag-5'>java</b>線程<b class='flag-5'>內(nèi)存</b>模型

    Java內(nèi)存模型及原理分析

    一、Java內(nèi)存模型 按照官方的說法:Java 虛擬機(jī)具有一個(gè)堆,堆是運(yùn)行時(shí)數(shù)據(jù)區(qū)域,所有類實(shí)例和數(shù)組的
    發(fā)表于 09-28 11:49 ?0次下載
    <b class='flag-5'>Java</b><b class='flag-5'>內(nèi)存</b>模型及原理分析

    利用StopWatch監(jiān)控Java代碼運(yùn)行時(shí)間和分析性能

    利用StopWatch監(jiān)控Java代碼運(yùn)行時(shí)間和分析性能。
    的頭像 發(fā)表于 07-21 16:51 ?2638次閱讀

    Java運(yùn)行時(shí)內(nèi)存區(qū)域硬件內(nèi)存關(guān)系2

    在上一篇文章中,我們了解了計(jì)算機(jī)由于各個(gè)硬件的讀取速度之間的巨大差距,和充分利用CPU的性能的手段方法,及其所帶來的一系列問題: 1. 為了充分壓榨CPU的性能, **CPU 會(huì)對(duì)指令亂序執(zhí)行或者語言的編譯器會(huì)指令重排** ,讓CPU一直工作不停歇,但同時(shí)會(huì)導(dǎo)致`有
    的頭像 發(fā)表于 02-09 14:41 ?268次閱讀
    <b class='flag-5'>Java</b><b class='flag-5'>運(yùn)行時(shí)</b><b class='flag-5'>內(nèi)存</b><b class='flag-5'>區(qū)域</b>與<b class='flag-5'>硬件</b><b class='flag-5'>內(nèi)存</b>的<b class='flag-5'>關(guān)系</b>2

    JVM運(yùn)行時(shí)數(shù)據(jù)區(qū)之堆內(nèi)存

    說一下 JVM 運(yùn)行時(shí)數(shù)據(jù)區(qū)吧,都有哪些區(qū)?分別是干什么的?
    的頭像 發(fā)表于 08-19 14:35 ?587次閱讀
    JVM<b class='flag-5'>運(yùn)行時(shí)</b>數(shù)據(jù)區(qū)之堆<b class='flag-5'>內(nèi)存</b>

    如何查看java程序的內(nèi)存分布

    要查看Java程序的內(nèi)存分布,首先需要了解Java程序運(yùn)行時(shí)內(nèi)存模型。 Java程序的
    的頭像 發(fā)表于 11-23 14:47 ?891次閱讀

    jvm內(nèi)存模型和內(nèi)存結(jié)構(gòu)

    內(nèi)存模型是指Java程序在運(yùn)行時(shí),JVM對(duì)內(nèi)存空間的組織和管理方式。它包括了線程私有的部分和線程共享的部分。 線程私有部分 線程私有部分主要包含了棧(Stack)和程序計(jì)數(shù)器(Prog
    的頭像 發(fā)表于 12-05 11:08 ?734次閱讀

    jvm運(yùn)行時(shí)內(nèi)存區(qū)域劃分

    內(nèi)存區(qū)域劃分對(duì)于了解Java程序的內(nèi)存使用非常重要,本文將詳細(xì)介紹JVM運(yùn)行時(shí)內(nèi)存
    的頭像 發(fā)表于 12-05 14:08 ?416次閱讀

    jvm管理的內(nèi)存包括哪幾個(gè)運(yùn)行時(shí)數(shù)據(jù)內(nèi)存

    JVM(Java虛擬機(jī))是Java程序的運(yùn)行環(huán)境,它提供了內(nèi)存管理機(jī)制來管理Java程序所需的運(yùn)行時(shí)
    的頭像 發(fā)表于 12-05 14:09 ?423次閱讀

    jvm內(nèi)存區(qū)域中,哪一塊是屬于線程共享

    是如何劃分的。JVM內(nèi)存區(qū)域主要分為以下幾個(gè)部分:程序計(jì)數(shù)器、Java虛擬機(jī)棧、本地方法棧、堆、方法區(qū)和運(yùn)行時(shí)常量池。其中,程序計(jì)數(shù)器、Java
    的頭像 發(fā)表于 12-05 14:14 ?1092次閱讀

    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 ?308次閱讀