java堆空間結(jié)構(gòu)是怎樣的?java對(duì)象在內(nèi)存中是怎樣分配的?
java堆指的是java虛擬機(jī)管理的一塊內(nèi)存,這塊內(nèi)存可以說(shuō)是最大的一塊,同時(shí)它也是被所有的線程共享的一塊區(qū)域,它的創(chuàng)建一般是在虛擬機(jī)啟動(dòng)的時(shí)候。java堆的作用就是存儲(chǔ)對(duì)象實(shí)例,差不多所有的對(duì)象實(shí)例都是在這里進(jìn)行內(nèi)存分配的。現(xiàn)在有很多的朋友對(duì)于java堆的空間結(jié)構(gòu)比較感興趣,那么java堆空間結(jié)構(gòu)是怎樣的?java對(duì)象在內(nèi)存中是怎樣分配的呢?下面新網(wǎng)就給朋友們?cè)敿?xì)的來(lái)分析一下。
Java堆可以細(xì)分為:新生代和老年代;在細(xì)致一點(diǎn)的有Eden空間、From Survivor空間、To Survivor空間等。
這樣劃分的目的是為了使 JVM 能夠更好的管理堆內(nèi)存中的對(duì)象,可以根據(jù)跟個(gè)年代的特點(diǎn)采用最適當(dāng)?shù)氖占惴āT谛律?,每次垃圾收集時(shí)都發(fā)現(xiàn)有大批的對(duì)象死去,只有少量存活,那就選用復(fù)制算法,只需要付出少量存活對(duì)象的復(fù)制成本就可以完成收集。而老年代中因?yàn)閷?duì)象存活率高、沒(méi)有額外空間對(duì)它進(jìn)行分配擔(dān)保,就必須使用"標(biāo)記---整理"算法來(lái)進(jìn)行回收。
絕大部分 Java 程序員應(yīng)該都見(jiàn)過(guò) "java.lang.OutOfMemoryError: PermGen space" 這個(gè)異常。這里的 "PermGen space"其實(shí)指的就是方法區(qū)。不過(guò)方法區(qū)和“PermGen space”又有著本質(zhì)的區(qū)別。前者是 JVM 的規(guī)范,而后者則是 JVM 規(guī)范的一種實(shí)現(xiàn),并且只有 HotSpot 才有 “PermGen space”,而對(duì)于其他類型的虛擬機(jī),如 JRockit(Oracle)、J9(IBM) 并沒(méi)有“PermGen space”。由于方法區(qū)主要存儲(chǔ)類的相關(guān)信息,所以對(duì)于動(dòng)態(tài)生成類的情況比較容易出現(xiàn)永久代的內(nèi)存溢出。最典型的場(chǎng)景就是,在 jsp 頁(yè)面比較多的情況,容易出現(xiàn)永久代內(nèi)存溢出。
在Java8中移除了永生代,取而代之是元空間(Metaspace) 移除了永久代(PermGen),替換為元空間(Metaspace)
永久代中的 class metadata 轉(zhuǎn)移到了 native memory(本地內(nèi)存,而不是虛擬機(jī));
永久代中的 interned Strings 和 class static variables 轉(zhuǎn)移到了 Java heap;
永久代參數(shù) (PermSize MaxPermSize) ->。
Java 對(duì)象在堆中的內(nèi)存結(jié)構(gòu)
我們知道,函數(shù)每次被調(diào)用時(shí),在內(nèi)存中都有自己的活動(dòng)記錄(activation record),稱為??臻g(stack). Java 的方法在調(diào)用時(shí)在 JVM 棧中為其分配一個(gè)棧幀(Java??臻g的一個(gè)片段),可以稱之為方法棧. 原則上,所有對(duì)象都在堆空間(Heap)中分配。
java對(duì)象在內(nèi)存中是怎樣分配的呢?
一旦對(duì)象在堆中分配了空間,那本質(zhì)上就是一系列的字節(jié),那么如何找到對(duì)象中某個(gè)特定的屬性域呢? 編譯器通過(guò)一個(gè)內(nèi)部表來(lái)保存每個(gè)域的偏移量。
子類對(duì)象和父類對(duì)象擁有同樣的內(nèi)存分布,當(dāng)然,子類對(duì)象需要更多的空間來(lái)存放新的屬性域。
這種分配方式的好處在于 Base類型的指針 如果指向了子類Derived的對(duì)象,依然在開頭的地方"看見(jiàn)"Base對(duì)象。
因此, 子類對(duì)象(Derived)采用 父類引用(Base) 來(lái)進(jìn)行的操作 保證是安全的,因此在運(yùn)行時(shí)不需要?jiǎng)討B(tài)地檢查 Base 引用的實(shí)際類型。
然而這種實(shí)現(xiàn)方式是沒(méi)有效率的,假若一個(gè)類有很多方法,那么每個(gè)對(duì)象就要持有20個(gè)指針,相應(yīng)的,每個(gè)對(duì)象都需要20個(gè)指針的內(nèi)存空間,這會(huì)導(dǎo)致創(chuàng)建對(duì)象變慢,所占空間更大。
Java虛擬機(jī)棧:線程私有的,與線程生命周期相同,用于存儲(chǔ)局部變量表,操作棧,方法返回值。局部變量表放著基本數(shù)據(jù)類型,還有對(duì)象的引用。
Java堆:所有線程共享的一塊內(nèi)存區(qū)域,對(duì)象實(shí)例幾乎都在這分配內(nèi)存。
方法區(qū):各個(gè)線程共享的區(qū)域,儲(chǔ)存虛擬機(jī)加載的類信息,常量,靜態(tài)變量,編譯后的代碼。拿HotSpot 虛擬機(jī)來(lái)說(shuō),在 JDK1.7的時(shí)候,方法區(qū)被稱作為永久代, 從JDK1.8開始,Metaspace (元空間)也就是我們所謂的方法區(qū)!
特別注意其中Java 堆和方法區(qū)是 線程共享的。其他都是 線程私有的。
聲明:免責(zé)聲明:本文內(nèi)容由互聯(lián)網(wǎng)用戶自發(fā)貢獻(xiàn)自行上傳,本網(wǎng)站不擁有所有權(quán),也不承認(rèn)相關(guān)法律責(zé)任。如果您發(fā)現(xiàn)本社區(qū)中有涉嫌抄襲的內(nèi)容,請(qǐng)發(fā)
送郵件至:operations@xinnet.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),本站將立刻刪除涉嫌侵權(quán)內(nèi)容。本站原創(chuàng)內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)
需注明出處:新網(wǎng)idc知識(shí)百科