關(guān)于JVM的面試傳送門(mén):https://blog.csdn.net/shengmingqijiquan/article/details/77508471 JVM內(nèi)存結(jié)構(gòu)主要?jiǎng)澐譃椋憾?,jvm棧,本地方法棧,,方法區(qū),,程序計(jì)數(shù)器 如下圖所示: 堆區(qū):簡(jiǎn)單概述:每個(gè)Java項(xiàng)目都有唯一對(duì)應(yīng)的一個(gè)JVM實(shí)例,每一個(gè)JVM實(shí)例又對(duì)應(yīng)著一個(gè)堆區(qū),。Java堆是被當(dāng)前應(yīng)用所有進(jìn)程所共享的,,在JVM啟動(dòng)時(shí)就創(chuàng)建了。堆區(qū)的目的就是存放所有new創(chuàng)建實(shí)例對(duì)象和數(shù)組,,由此可見(jiàn)堆對(duì)于當(dāng)前應(yīng)用來(lái)說(shuō)是全局的,。 PS:這也就解釋了假設(shè)有A,B兩個(gè)Java項(xiàng)目,A項(xiàng)目有a,b,c三個(gè)類(lèi),,a類(lèi)可以調(diào)用b,c三個(gè)類(lèi),,但是在B項(xiàng)目就不可以使用a,b,c三個(gè)類(lèi)了 堆區(qū)的特點(diǎn):堆的主要優(yōu)勢(shì)是靈活性,它可以的動(dòng)態(tài)的分配內(nèi)存,。編譯器不需要知道需要?jiǎng)?chuàng)建對(duì)象的時(shí)候需要分配多少內(nèi)存給它,,也不需要知道該對(duì)象的生命周期。new一個(gè)對(duì)象的時(shí)候會(huì)自動(dòng)從堆中分配內(nèi)存給它,,然后如果長(zhǎng)時(shí)間沒(méi)有引用指向該對(duì)象時(shí),,JVM垃圾回收機(jī)制會(huì)在某個(gè)合適的時(shí)間點(diǎn)回收它,。 Java堆是jvm管理內(nèi)存中最大的一塊,它也是JVM垃圾回收的主要區(qū)域,。雖然JVM垃圾回收機(jī)制會(huì)在某個(gè)合適的時(shí)間點(diǎn)自動(dòng)回收沒(méi)有引用指向的對(duì)象,,但是作為java開(kāi)發(fā)人員,掌握垃圾回收機(jī)制是很重要的,,日后還要去學(xué)習(xí)這個(gè).... 本地方法棧:虛擬機(jī)執(zhí)行Native方法服務(wù),,執(zhí)行不是用Java代碼寫(xiě)的如C寫(xiě)的 虛擬機(jī)棧區(qū):當(dāng)程序進(jìn)入到一個(gè)方法時(shí),會(huì)為這個(gè)方法分配一個(gè)私有存儲(chǔ)空間,,該空間為JVM棧,。該線程為私有的。就好比你在a()方法中定義了int t = 1;但是在b方法中就不能直接用t,。但是棧里面的數(shù)據(jù)是可以共享的,。當(dāng)方法結(jié)束時(shí),該區(qū)域就釋放了 棧的速度比堆要快,,僅次于寄存器,。但是缺少靈活性,其數(shù)據(jù)大小和生存周期可知(這些字面值固定定義在某個(gè)程序塊里面,,程序塊退出后,,字段值就消失了) 至于為什么函數(shù)調(diào)用要采用棧調(diào)用,,主要是契合數(shù)據(jù)結(jié)構(gòu)中棧的先進(jìn)后出原則,,可以看下這篇連接:https://www.zhihu.com/question/34499262/answer/59415153 實(shí)例分析一:棧里面的數(shù)據(jù)是共享的 int a=1; int b=1; 編譯器預(yù)先處理int a =1;首先在棧中創(chuàng)建一個(gè)變量為a的引用,然后去棧中查找有沒(méi)有字面值為1的地址,,沒(méi)有就開(kāi)辟一個(gè)存放字面值為1的地址,。接著執(zhí)行b=1;創(chuàng)建一個(gè)變量為b的引用,由于已經(jīng)存在字面值為1的地址了,,所以b直接指向該地址,。所以:出現(xiàn)了a,b同時(shí)指向1這個(gè)地址 特別注意:字面值的引用與對(duì)象的引用是不一樣的,假設(shè)兩個(gè)類(lèi)對(duì)象的引用指向同一個(gè)對(duì)象,,如果一個(gè)引用對(duì)象修改了這個(gè)類(lèi)的內(nèi)部狀態(tài),,那么另一個(gè)引用對(duì)象也會(huì)即可反映出這個(gè)變化;而字面值引用則不會(huì),,假設(shè)在寫(xiě)上b=2,那么b引用會(huì)重新去JVM棧中去尋找字面值為2的地址,,找不到則重新開(kāi)辟一個(gè)地址來(lái)存儲(chǔ)2,然后b引用在指向它 public class test2 { public static void main(String[] args) { int a = 1; int b = 1; // 1.創(chuàng)建變量為a的引用,,在JVM棧中開(kāi)辟字面值為1的地址,,a在指向它 // 2.創(chuàng)建變量為b的引用,棧中已存在字面值為1的地址,,b直接指向該地址,。所以a,b地址相同 System.out.println(a == b); //true b = 2; System.out.println(a==b); //false } } public class test { int num = 1; public static void main(String[] args) { // 創(chuàng)建變量為a的對(duì)象引用,,new test()在堆中分配內(nèi)存存儲(chǔ)該對(duì)象,a再指向堆區(qū)中該對(duì)象的地址 test a = new test(); // 創(chuàng)建變量值為b的引用對(duì)象,,指向a指向的堆區(qū)中地址 test b = a; System.out.println(a == b); b.num = 2; //這里就屬于另一個(gè)對(duì)象引用修改了該對(duì)象的內(nèi)部狀態(tài),,導(dǎo)致a受影響了 System.out.println(a.num); // 2 如果是test b = new test()則輸出1,因?yàn)橹赶虻牟皇峭粋€(gè)對(duì)象 // 這里又在堆區(qū)中給test對(duì)象分配了內(nèi)存 test c = new test(); System.out.println(a == c); } } ?關(guān)于包裝類(lèi)型數(shù)據(jù):如Integer,Double,Float等將基本數(shù)據(jù)類(lèi)型包裝起來(lái)的類(lèi),,它們存在于堆區(qū)中,。Java用new()來(lái)顯示的告訴編譯器要?jiǎng)?chuàng)建。之后將對(duì)包裝類(lèi)型做一下整理,,尤其是地址指向 方法區(qū):方法區(qū)也同堆一樣是被所有線程所共享的,,它里面存放著satic修飾的代碼和類(lèi)信息,常量(final修飾) 程序計(jì)數(shù)器:線程私有,,占用內(nèi)存小,。 字節(jié)碼行號(hào)指示器,解釋器通過(guò)它來(lái)選取下一條執(zhí)行的字節(jié)碼指令
不會(huì)有 OutOfMemoryError ? 來(lái)源:http://www./content-3-175551.html |
|
來(lái)自: 印度阿三17 > 《開(kāi)發(fā)》