Java作為一種面向?qū)ο蟮纳胛疲缙脚_語言宋梧,其對象匣沼、內(nèi)存等一直是比較難的知識點(diǎn)。而且很多概念的名稱看起來又那么相似捂龄,很多人會(huì)傻傻分不清楚释涛。比如本文我們要討論的JVM內(nèi)存結(jié)構(gòu)、Java內(nèi)存模型和Java對象模型倦沧,這就是三個(gè)截然不同的概念唇撬,但是很多人容易弄混。
可以這樣說刀脏,很多高級開發(fā)甚至都搞不不清楚JVM內(nèi)存結(jié)構(gòu)局荚、Java內(nèi)存模型和Java對象模型這三者的概念及其間的區(qū)別超凳。甚至我見過有些面試官自己也搞的不是太清楚愈污。不信的話,你去網(wǎng)上搜索Java內(nèi)存模型轮傍,還會(huì)有很多文章的內(nèi)容其實(shí)介紹的是JVM內(nèi)存結(jié)構(gòu)暂雹。
首先,這三個(gè)概念是完全不同的三個(gè)概念创夜。本文主要對這三個(gè)概念加以區(qū)分以及簡單介紹杭跪。其中每一個(gè)知識點(diǎn)都可以單獨(dú)寫一篇文章,本文并不會(huì)深入介紹驰吓,感興趣的朋友可以自行百度學(xué)習(xí)涧尿。
JVM內(nèi)存結(jié)構(gòu)
我們都知道,Java代碼是要運(yùn)行在虛擬機(jī)上的檬贰,而虛擬機(jī)在執(zhí)行Java程序的過程中會(huì)把所管理的內(nèi)存劃分為若干個(gè)不同的數(shù)據(jù)區(qū)域姑廉,這些區(qū)域都有各自的用途。其中有些區(qū)域隨著虛擬機(jī)進(jìn)程的啟動(dòng)而存在翁涤,而有些區(qū)域則依賴用戶線程的啟動(dòng)和結(jié)束而建立和銷毀桥言。在《Java虛擬機(jī)規(guī)范(Java SE 8)》中描述了JVM運(yùn)行時(shí)內(nèi)存區(qū)域結(jié)構(gòu)如下:
各個(gè)區(qū)域的功能不是本文重點(diǎn)萌踱,就不在這里詳細(xì)介紹了。這里簡單提幾個(gè)需要特別注意的點(diǎn):
1号阿、以上是Java虛擬機(jī)規(guī)范并鸵,不同的虛擬機(jī)實(shí)現(xiàn)會(huì)各有不同,但是一般會(huì)遵守規(guī)范扔涧。
2园担、規(guī)范中定義的方法區(qū),只是一種概念上的區(qū)域扰柠,并說明了其應(yīng)該具有什么功能粉铐。但是并沒有規(guī)定這個(gè)區(qū)域到底應(yīng)該處于何處。所以卤档,對于不同的虛擬機(jī)實(shí)現(xiàn)來說蝙泼,是由一定的自由度的。
3劝枣、不同版本的方法區(qū)所處位置不同汤踏,上圖中劃分的是邏輯區(qū)域,并不是絕對意義上的物理區(qū)域舔腾。因?yàn)槟承┌姹镜腏DK中方法區(qū)其實(shí)是在堆中實(shí)現(xiàn)的溪胶。
4、運(yùn)行時(shí)常量池用于存放編譯期生成的各種字面量和符號應(yīng)用稳诚。但是哗脖,Java語言并不要求常量只有在編譯期才能產(chǎn)生。比如在運(yùn)行期扳还,String.intern也會(huì)把新的常量放入池中才避。
5、除了以上介紹的JVM運(yùn)行時(shí)內(nèi)存外氨距,還有一塊內(nèi)存區(qū)域可供使用桑逝,那就是直接內(nèi)存。Java虛擬機(jī)規(guī)范并沒有定義這塊內(nèi)存區(qū)域俏让,所以他并不由JVM管理楞遏,是利用本地方法庫直接在堆外申請的內(nèi)存區(qū)域。
6首昔、堆和棧的數(shù)據(jù)劃分也不是絕對的寡喝,如HotSpot的JIT會(huì)針對對象分配做相應(yīng)的優(yōu)化。
如上勒奇,做個(gè)總結(jié)预鬓,JVM內(nèi)存結(jié)構(gòu),由Java虛擬機(jī)規(guī)范定義撬陵。描述的是Java程序執(zhí)行過程中珊皿,由JVM管理的不同數(shù)據(jù)區(qū)域网缝。各個(gè)區(qū)域有其特定的功能。
Java內(nèi)存模型
Java內(nèi)存模型看上去和Java內(nèi)存結(jié)構(gòu)(JVM內(nèi)存結(jié)構(gòu))差不多蟋定,很多人會(huì)誤以為兩者是一回事兒粉臊,這也就導(dǎo)致面試過程中經(jīng)常答非所為。
在前面的關(guān)于JVM的內(nèi)存結(jié)構(gòu)的圖中驶兜,我們可以看到扼仲,其中Java堆和方法區(qū)的區(qū)域是多個(gè)線程共享的數(shù)據(jù)區(qū)域。也就是說抄淑,多個(gè)線程可能可以操作保存在堆或者方法區(qū)中的同一個(gè)數(shù)據(jù)屠凶。這也就是我們常說的“Java的線程間通過共享內(nèi)存進(jìn)行通信”。
Java內(nèi)存模型是根據(jù)英文Java Memory Model(JMM)翻譯過來的肆资。其實(shí)JMM并不像JVM內(nèi)存結(jié)構(gòu)一樣是真實(shí)存在的矗愧。他只是一個(gè)抽象的概念。JSR-133: Java Memory Model and Thread Specification中描述了郑原,JMM是和多線程相關(guān)的唉韭,他描述了一組規(guī)則或規(guī)范,這個(gè)規(guī)范定義了一個(gè)線程對共享變量的寫入時(shí)對另一個(gè)線程是可見的犯犁。
那么属愤,簡單總結(jié)下,Java的多線程之間是通過共享內(nèi)存進(jìn)行通信的酸役,而由于采用共享內(nèi)存進(jìn)行通信住诸,在通信過程中會(huì)存在一系列如可見性、原子性涣澡、順序性等問題贱呐,而JMM就是圍繞著多線程通信以及與其相關(guān)的一系列特性而建立的模型。JMM定義了一些語法集暑塑,這些語法集映射到Java語言中就是volatile吼句、synchronized等關(guān)鍵字锅必。
在Java中事格,JMM是一個(gè)非常重要的概念,正是由于有了JMM搞隐,Java的并發(fā)編程才能避免很多問題驹愚。這里就不對Java內(nèi)存模型做更加詳細(xì)的介紹了,想了解更多的朋友可以參考《Java并發(fā)編程的藝術(shù)》劣纲。
Java對象模型
Java是一種面向?qū)ο蟮恼Z言逢捺,而Java對象在JVM中的存儲(chǔ)也是有一定的結(jié)構(gòu)的。而這個(gè)關(guān)于Java對象自身的存儲(chǔ)模型稱之為Java對象模型癞季。
HotSpot虛擬機(jī)中劫瞳,設(shè)計(jì)了一個(gè)OOP-Klass Model倘潜。OOP(Ordinary Object Pointer)指的是普通對象指針,而Klass用來描述對象實(shí)例的具體類型志于。
每一個(gè)Java類涮因,在被JVM加載的時(shí)候,JVM會(huì)給這個(gè)類創(chuàng)建一個(gè)instanceKlass伺绽,保存在方法區(qū)养泡,用來在JVM層表示該Java類。當(dāng)我們在Java代碼中奈应,使用new創(chuàng)建一個(gè)對象的時(shí)候澜掩,JVM會(huì)創(chuàng)建一個(gè)instanceOopDesc對象,這個(gè)對象中包含了對象頭以及實(shí)例數(shù)據(jù)杖挣。
這就是一個(gè)簡單的Java對象的OOP-Klass模型肩榕,即Java對象模型。
總結(jié)
我們再來區(qū)分下JVM內(nèi)存結(jié)構(gòu)惩妇、 Java內(nèi)存模型 以及 Java對象模型 三個(gè)概念点把。
JVM內(nèi)存結(jié)構(gòu),和Java虛擬機(jī)的運(yùn)行時(shí)區(qū)域有關(guān)屿附。 Java內(nèi)存模型郎逃,和Java的并發(fā)編程有關(guān)。 Java對象模型挺份,和Java對象在虛擬機(jī)中的表現(xiàn)形式有關(guān)褒翰。