一、簡介
??Java 內(nèi)存模型(Java Memory Model,JMM)是一種規(guī)范,定義了 Java 程序中多線程并發(fā)訪問共享變量時(shí)的行為和規(guī)則。
二、JVM內(nèi)存區(qū)域
??線程共享:方法區(qū)、堆
??線程獨(dú)有:棧、程序計(jì)數(shù)器
2.1 方法區(qū)
??方法區(qū)是JVM中的一塊內(nèi)存區(qū)域,在JVM啟動(dòng)時(shí)被創(chuàng)建,與堆內(nèi)存分開管理。方法區(qū)的大小可以通過-XX:MetaspaceSize
和-XX:MaxMetaspaceSize
參數(shù)進(jìn)行調(diào)整。
??存儲的內(nèi)容有:
- 類的結(jié)構(gòu)信息:包括類的字段、方法、父類、接口等
- 常量池
- 靜態(tài)變量
- 即時(shí)編譯器編譯后的代碼
2.3.2 永久代和元空間
??在Java虛擬機(jī)(JVM)的不同版本中,永久代(Permanent Generation)和元空間(Metaspace)是用于存儲類相關(guān)信息的內(nèi)存區(qū)域,都是實(shí)現(xiàn)方法區(qū)的方式。
-
永久代(Permanent Generation):
1.8版本以前有永久代,永久代放在JVM內(nèi)存中,在某些情況下存在一些問題。例如,如果加載的類過多或過大,永久代的大小可能會(huì)不夠,導(dǎo)致OutOfMemoryError。由于這些問題,從JDK 8開始,永久代被元空間所取代。 -
元空間(Metaspace):
元空間是JDK 8及更高版本中取代永久代的新的內(nèi)存區(qū)域。元空間同樣用于存儲類的結(jié)構(gòu)信息、常量池、靜態(tài)變量和即時(shí)編譯器編譯后的代碼等。與永久代不同,元空間的大小不再受限于固定的內(nèi)存大小,而是根據(jù)應(yīng)用程序的需求進(jìn)行動(dòng)態(tài)分配。元空間的數(shù)據(jù)存儲在本地內(nèi)存(Native Memory)中,而不是像永久代那樣存儲在Java運(yùn)行時(shí)內(nèi)存中。這意味著元空間的大小受限于可用的物理內(nèi)存。如果元空間的內(nèi)存耗盡,JVM依然會(huì)拋出OutOfMemoryError。
2.2 堆
??堆內(nèi)存是Java程序中最大的一塊內(nèi)存區(qū)域,用于存儲對象實(shí)例和數(shù)組。堆內(nèi)存可以劃分為不同的代,包括新生代(Eden區(qū)、Survivor區(qū))和老年代。新創(chuàng)建的對象會(huì)被分配到新生代的Eden區(qū),經(jīng)過垃圾回收后,仍然存活的對象會(huì)被移到Survivor區(qū),最終進(jìn)入老年代。
1.8版本的堆結(jié)構(gòu):
??新生代與老年代的比例是1:2
??Eden、s0、s1的比例是8比1比1
1.9及以后的堆結(jié)構(gòu)
??G1將內(nèi)存劃分成了多個(gè)大小相等的Region(默認(rèn)是512K),Region邏輯上連續(xù),物理內(nèi)存地址不連續(xù)。同時(shí)每個(gè)Region被標(biāo)記成E、S、O、H,分別表示Eden、Survivor、Old、Humongous。其中E、S屬于年輕代,O與H屬于老年代。
??H表示Humongous。從字面上就可以理解表示大的對象(下面簡稱H對象)。當(dāng)分配的對象大于等于Region大小的一半的時(shí)候就會(huì)被認(rèn)為是巨型對象。H對象默認(rèn)分配在老年代,可以防止GC的時(shí)候大對象的內(nèi)存拷貝。
2.1.2 對象的創(chuàng)建和銷毀
??在Java中,對象的創(chuàng)建通過new
關(guān)鍵字實(shí)現(xiàn)。當(dāng)調(diào)用new
關(guān)鍵字創(chuàng)建對象時(shí),JVM會(huì)在堆內(nèi)存中分配一塊內(nèi)存空間用于存儲對象的實(shí)例變量,并執(zhí)行構(gòu)造方法對對象進(jìn)行初始化。對象的銷毀由垃圾回收器負(fù)責(zé),當(dāng)對象不再被引用時(shí),垃圾回收器會(huì)回收該對象的內(nèi)存空間。
??創(chuàng)建流程:
- ?先檢查這個(gè)指令的參數(shù)是否能在常量池中定位到?個(gè)類的符號引?
- 檢查這個(gè)符號引?代表的類是否已被加載、解析和初始化過。如果沒有,就先執(zhí)?相應(yīng)的類加載過程
- 類加載檢查通過后,接下來虛擬機(jī)將為新?對象分配內(nèi)存。
- 內(nèi)存分配完成之后,虛擬機(jī)將分配到的內(nèi)存空間(但不包括對象頭)都初始化為零值。
- 接下來設(shè)置對象頭,請求頭?包含了對象是哪個(gè)類的實(shí)例、如何才能找到類的元數(shù)據(jù)信息、對象的 哈希碼、對象的 GC 分代年齡等信息
2.2 棧內(nèi)存
??棧分為本地方法棧和java方法棧。
??每個(gè)線程在創(chuàng)建時(shí)都會(huì)創(chuàng)建一個(gè)java方法棧,棧內(nèi)會(huì)保存一個(gè)個(gè)的棧幀,每個(gè)棧幀對應(yīng)一個(gè)方法。
??棧采用先進(jìn)后出的數(shù)據(jù)結(jié)構(gòu),方法的調(diào)用和返回都是通過棧幀的入棧和出棧來實(shí)現(xiàn)的。
2.2.1 棧幀的組成和作用
??棧幀是棧內(nèi)存中的一個(gè)元素,用于存儲方法的局部變量表、操作數(shù)棧、動(dòng)態(tài)鏈接、方法返回地址等信息。局部變量表用于存儲方法的局部變量和參數(shù),操作數(shù)棧用于存儲方法執(zhí)行過程中的操作數(shù)和中間結(jié)果。棧幀的作用是提供方法調(diào)用和執(zhí)行的環(huán)境,保證方法的獨(dú)立性和數(shù)據(jù)的隔離性。文章來源:http://www.zghlxwxcb.cn/news/detail-650922.html
2.2.2 棧的特點(diǎn)
- 棧是線程私有的
- 一個(gè)方法開始執(zhí)行棧幀入棧、方法執(zhí)行完對應(yīng)的棧幀就出棧,所以虛擬機(jī)棧不需要進(jìn)行垃圾回收
- 虛擬機(jī)棧存在OutOfMemoryError、以及StackOverflowError
- 線程太多,就可能會(huì)出現(xiàn)OutOfMemoryError,線程創(chuàng)建時(shí)沒有足夠的內(nèi)存去創(chuàng)建虛擬機(jī)棧了
- 方法調(diào)用層次太多,就可能會(huì)出現(xiàn)StackOverflowError(棧的大小有限)
- 可以通過-Xss來設(shè)置虛擬機(jī)棧的大小
2.4 程序計(jì)數(shù)器
2.4.1 程序計(jì)數(shù)器的作用和使用場景
??程序計(jì)數(shù)器是一塊較小的內(nèi)存區(qū)域,用于存儲當(dāng)前線程執(zhí)行的字節(jié)碼指令的地址。程序計(jì)數(shù)器在多線程環(huán)境下,每個(gè)線程都有獨(dú)立的程序計(jì)數(shù)器,用于記錄各個(gè)線程執(zhí)行的位置,保證線程切換后能正確恢復(fù)執(zhí)行。文章來源地址http://www.zghlxwxcb.cn/news/detail-650922.html
到了這里,關(guān)于JVM 內(nèi)存結(jié)構(gòu)快速入門的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!