溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶(hù)服務(wù)條款》

java中JVM內(nèi)存模型的介紹

發(fā)布時(shí)間:2021-06-26 09:27:49 來(lái)源:億速云 閱讀:160 作者:chen 欄目:大數(shù)據(jù)

這篇文章主要講解了“java中JVM內(nèi)存模型的介紹”,文中的講解內(nèi)容簡(jiǎn)單清晰,易于學(xué)習(xí)與理解,下面請(qǐng)大家跟著小編的思路慢慢深入,一起來(lái)研究和學(xué)習(xí)“java中JVM內(nèi)存模型的介紹”吧!

JVM 的重要性

首先你應(yīng)該知道,運(yùn)行一個(gè) Java 應(yīng)用程序,我們必須要先安裝 JDK 或者 JRE 。這是因?yàn)?Java 應(yīng)用在編譯后會(huì)變成字節(jié)碼,然后通過(guò)字節(jié)碼運(yùn)行在 JVM 中,而 JVM 是 JRE 的核心組成部分。

優(yōu)點(diǎn)

JVM 不僅承擔(dān)了 Java 字節(jié)碼的分析(JIT compiler)和執(zhí)行(Runtime),同時(shí)也內(nèi)置了自動(dòng)內(nèi)存分配管理機(jī)制。這個(gè)機(jī)制可以大大降低手動(dòng)分配回收機(jī)制可能帶來(lái)的內(nèi)存泄露和內(nèi)存溢出風(fēng)險(xiǎn),使 Java 開(kāi)發(fā)人員不需要關(guān)注每個(gè)對(duì)象的內(nèi)存分配以及回收,從而更專(zhuān)注于業(yè)務(wù)本身。

缺點(diǎn)

這個(gè)機(jī)制在提升 Java 開(kāi)發(fā)效率的同時(shí),也容易使 Java 開(kāi)發(fā)人員過(guò)度依賴(lài)于自動(dòng)化,弱化對(duì)內(nèi)存的管理能力,這樣系統(tǒng)就很容易發(fā)生 JVM 的堆內(nèi)存異常、垃圾回收(GC)的不合適以及 GC 次數(shù)過(guò)于頻繁等問(wèn)題,這些都將直接影響到應(yīng)用服務(wù)的性能。

內(nèi)存模型

JVM 內(nèi)存模型共分為5個(gè)區(qū):堆(Heap)、方法區(qū)(Method Area)程序計(jì)數(shù)器(Program Counter Register)、虛擬機(jī)棧(VM Stack)本地方法棧(Native Method Stack)。

java中JVM內(nèi)存模型的介紹

其中,堆(Heap)、方法區(qū)(Method Area)線(xiàn)程共享,程序計(jì)數(shù)器(Program Counter Register)、虛擬機(jī)棧(VM Stack)本地方法棧(Native Method Stack)線(xiàn)程隔離。

堆(Heap)

堆是 JVM 內(nèi)存中最大的一塊內(nèi)存空間,該內(nèi)存被所有線(xiàn)程共享,幾乎所有對(duì)象和數(shù)組都被分配到了堆內(nèi)存中。

堆被劃分為新生代和老年代,新生代又被進(jìn)一步劃分為 Eden 區(qū)和 Survivor 區(qū),最后 Survivor 由 From Survivor 和 To Survivor 組成。

隨著 Java 版本的更新,其內(nèi)容又有了一些新的變化: >在 Java6 版本中,永久代在非堆內(nèi)存區(qū);到了 Java7 版本,永久代的靜態(tài)變量和運(yùn)行時(shí)常量池被合并到了堆中;而到了 Java8,永久代被元空間(處于本地內(nèi)存)取代了。

java中JVM內(nèi)存模型的介紹

為什么要用元空間替換永久代呢?

  1. 為了融合 HotSpot JVM 與 JRockit VM,因?yàn)?JRockit 沒(méi)有永久代,所以不需要配置永久代。

  2. 永久代內(nèi)存經(jīng)常不夠用或發(fā)生內(nèi)存溢出(應(yīng)該是 JVM 中占用內(nèi)存最大的一塊),產(chǎn)生異常 java.lang.OutOfMemoryError: PermGen。在 JDK1.7 版本中,指定的 PermGen 區(qū)大小為 8M,由于 PermGen 中類(lèi)的元數(shù)據(jù)信息在每次 FullGC 的時(shí)候都可能被收集,回收率都偏低,成績(jī)很難令人滿(mǎn)意;還有,為 PermGen 分配多大的空間很難確定,PermSize 的大小依賴(lài)于很多因素,比如,JVM 加載的 class 總數(shù)、常量池的大小和方法的大小等。

看到這兒,自然就想到了 GC 回收算法,不用急,我會(huì)在之后的文章中進(jìn)行講解,現(xiàn)在還是以 JVM 內(nèi)存模型為主。

方法區(qū)(Method Area)

什么是方法區(qū)? >方法區(qū)主要是用來(lái)存放已被虛擬機(jī)加載的類(lèi)相關(guān)信息,包括類(lèi)信息、常量池(字符串常量池以及所有基本類(lèi)型都有其相應(yīng)的常量池)、運(yùn)行時(shí)常量池。這其中,類(lèi)信息又包括了類(lèi)的版本、字段、方法、接口和父類(lèi)等信息。

類(lèi)信息

JVM 在執(zhí)行某個(gè)類(lèi)的時(shí)候,必須經(jīng)過(guò)加載、連接、初始化,而連接又包括驗(yàn)證、準(zhǔn)備、解析三個(gè)階段。

在加載類(lèi)的時(shí)候,JVM 會(huì)先加載 class 文件,而在 class 文件中便有類(lèi)的版本、字段、方法和接口等描述信息,這就是類(lèi)信息。

常量池

在 class 文件中,除了類(lèi)信息,還有一項(xiàng)信息是常量池 (Constant Pool Table),用于存放編譯期間生成的各種字面量符號(hào)引用。

字面量符號(hào)引用又是什么呢?

字面量包括字符串(String a=“b”)、基本類(lèi)型的常量(final 修飾的變量),符號(hào)引用則包括類(lèi)和方法的全限定名(例如 String 這個(gè)類(lèi),它的全限定名就是 Java/lang/String)、字段的名稱(chēng)和描述符以及方法的名稱(chēng)和描述符。

運(yùn)行時(shí)常量池

當(dāng)類(lèi)加載到內(nèi)存后,JVM 就會(huì)將 class 文件常量池中的內(nèi)容存放到運(yùn)行時(shí)常量池中;在解析階段,JVM 會(huì)把符號(hào)引用替換為直接引用(對(duì)象的索引值)。

例如: >類(lèi)中的一個(gè)字符串常量在 class 文件中時(shí),存放在 class 文件常量池中的。 > >在 JVM 加載完類(lèi)之后,JVM 會(huì)將這個(gè)字符串常量放到運(yùn)行時(shí)常量池中,并在解析階段,指定該字符串對(duì)象的索引值。

運(yùn)行時(shí)常量池是全局共享的,多個(gè)類(lèi)共用一個(gè)運(yùn)行時(shí)常量池,因此,class 文件中常量池多個(gè)相同的字符串在運(yùn)行時(shí)常量池只會(huì)存在一份。

講到這里,大家是不是有些頭暈了,說(shuō)實(shí)話(huà),我在看到這些內(nèi)容的時(shí)候,也是云里霧里的,這里舉個(gè)例子幫助大家理解:

    public static void main(String[] args) {
        String str = "Hello";
        System.out.println((str == ("Hel" + "lo")));

        String loStr = "lo";
        System.out.println((str == ("Hel" + loStr)));

        System.out.println(str == ("Hel" + loStr).intern());
    }

其運(yùn)行結(jié)果為:

true
false
true

第一個(gè)為 true,是因?yàn)樵诰幾g成 class 文件時(shí),能夠識(shí)別為同一字符串的, JVM 會(huì)將其自動(dòng)優(yōu)化成字符串常量,引用自同一 String 對(duì)象。

第二個(gè)為 false,是因?yàn)樵谶\(yùn)行時(shí)創(chuàng)建的字符串具有獨(dú)立的內(nèi)存地址,所以不引用自同一 String 對(duì)象。

最后一個(gè)為 true,是因?yàn)?String 的 intern() 方法會(huì)查找在常量池中是否存在一個(gè)相等(調(diào)用 equals() 方法結(jié)果相等)的字符串,如果有則返回該字符串的引用,如果沒(méi)有則添加自己的字符串進(jìn)入常量池。

涉及到的Error
  1. OutOfMemoryError出現(xiàn)在方法區(qū)無(wú)法滿(mǎn)足內(nèi)存分配需求的時(shí)候,比如一直往常量池中加入數(shù)據(jù),運(yùn)行時(shí)常量池就會(huì)溢出,從而報(bào)錯(cuò)。

程序計(jì)數(shù)器(Program Counter Register)

程序計(jì)數(shù)器是一塊很小的內(nèi)存空間,主要用來(lái)記錄各個(gè)線(xiàn)程執(zhí)行的字節(jié)碼的地址,例如,分支、循環(huán)、跳轉(zhuǎn)、異常、線(xiàn)程恢復(fù)等都依賴(lài)于計(jì)數(shù)器。

由于 Java 是多線(xiàn)程語(yǔ)言,當(dāng)執(zhí)行的線(xiàn)程數(shù)量超過(guò) CPU 數(shù)量時(shí),線(xiàn)程之間會(huì)根據(jù)時(shí)間片輪詢(xún)爭(zhēng)奪 CPU 資源。如果一個(gè)線(xiàn)程的時(shí)間片用完了,或者是其它原因?qū)е逻@個(gè)線(xiàn)程的 CPU 資源被提前搶奪,那么這個(gè)退出的線(xiàn)程就需要單獨(dú)的一個(gè)程序計(jì)數(shù)器,來(lái)記錄下一條運(yùn)行的指令。

由此可見(jiàn),程序計(jì)數(shù)器和上下文切換有關(guān)。

虛擬機(jī)棧(VM Stack)

>虛擬機(jī)棧是線(xiàn)程私有的內(nèi)存空間,它和 Java 線(xiàn)程一起創(chuàng)建。 > >當(dāng)創(chuàng)建一個(gè)線(xiàn)程時(shí),會(huì)在虛擬機(jī)棧中申請(qǐng)一個(gè)線(xiàn)程棧,用來(lái)保存方法的局部變量、操作數(shù)棧、動(dòng)態(tài)鏈接方法和返回地址等信息,并參與方法的調(diào)用和返回。 > >每一個(gè)方法的調(diào)用都伴隨著棧幀的入棧操作,方法的返回則是棧幀的出棧操作。

可以這么理解,虛擬機(jī)棧針對(duì)當(dāng)前 Java 應(yīng)用中所有線(xiàn)程,都有一個(gè)其相應(yīng)的線(xiàn)程棧,每一個(gè)線(xiàn)程棧都互相獨(dú)立、互不影響,里面存儲(chǔ)了該線(xiàn)程中獨(dú)有的信息。

涉及到的Error
  1. StackOverflowError出現(xiàn)在棧內(nèi)存設(shè)置成固定值的時(shí)候,當(dāng)程序執(zhí)行需要的棧內(nèi)存超過(guò)設(shè)定的固定值時(shí)會(huì)拋出這個(gè)錯(cuò)誤。

  2. OutOfMemoryError出現(xiàn)在棧內(nèi)存設(shè)置成動(dòng)態(tài)增長(zhǎng)的時(shí)候,當(dāng)JVM嘗試申請(qǐng)的內(nèi)存大小超過(guò)了其可用內(nèi)存時(shí)會(huì)拋出這個(gè)錯(cuò)誤。

本地方法棧(Native Method Stack)

>本地方法棧跟虛擬機(jī)棧的功能類(lèi)似,虛擬機(jī)棧用于管理 Java 方法的調(diào)用,而本地方法棧則用于管理本地方法的調(diào)用。 > >但本地方法并不是用 Java 實(shí)現(xiàn)的,而是由 C 語(yǔ)言實(shí)現(xiàn)的。

也就是說(shuō),本地方法棧中并沒(méi)有我們寫(xiě)的代碼邏輯,其由native修飾,由 C 語(yǔ)言實(shí)現(xiàn)。

感謝各位的閱讀,以上就是“java中JVM內(nèi)存模型的介紹”的內(nèi)容了,經(jīng)過(guò)本文的學(xué)習(xí)后,相信大家對(duì)java中JVM內(nèi)存模型的介紹這一問(wèn)題有了更深刻的體會(huì),具體使用情況還需要大家實(shí)踐驗(yàn)證。這里是億速云,小編將為大家推送更多相關(guān)知識(shí)點(diǎn)的文章,歡迎關(guān)注!

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI