關於JVM的面試傳送門:http://www.javashuo.com/article/p-fhbpjqer-ha.htmlhtml
JVM內存結構主要劃分爲:堆,jvm棧,本地方法棧,方法區,程序計數器java
以下圖所示:面試
簡單概述:每一個Java項目都有惟一對應的一個JVM實例,每個JVM實例又對應着一個堆區。Java堆是被當前應用全部進程所共享的,在JVM啓動時就建立了。堆區的目的就是存放全部new建立實例對象和數組,因而可知堆對於當前應用來講是全局的。數組
PS:這也就解釋了假設有A,B兩個Java項目,A項目有a,b,c三個類,a類能夠調用b,c三個類,可是在B項目就不能夠使用a,b,c三個類了數據結構
堆區的特色:堆的主要優點是靈活性,它能夠的動態的分配內存。編譯器不須要知道須要建立對象的時候須要分配多少內存給它,也不須要知道該對象的生命週期。new一個對象的時候會自動從堆中分配內存給它,而後若是長時間沒有引用指向該對象時,JVM垃圾回收機制會在某個合適的時間點回收它。jvm
Java堆是jvm管理內存中最大的一塊,它也是JVM垃圾回收的主要區域。雖然JVM垃圾回收機制會在某個合適的時間點自動回收沒有引用指向的對象,可是做爲java開發人員,掌握垃圾回收機制是很重要的,往後還要去學習這個....函數
虛擬機執行Native方法服務,執行不是用Java代碼寫的如C寫的學習
當程序進入到一個方法時,會爲這個方法分配一個私有存儲空間,該空間爲JVM棧。該線程爲私有的。就比如你在a()方法中定義了int t = 1;可是在b方法中就不能直接用t。可是棧裏面的數據是能夠共享的。當方法結束時,該區域就釋放了spa
棧的速度比堆要快,僅次於寄存器。可是缺乏靈活性,其數據大小和生存週期可知(這些字面值固定定義在某個程序塊裏面,程序塊退出後,字段值就消失了).net
至於爲何函數調用要採用棧調用,主要是契合數據結構中棧的先進後出原則,能夠看下這篇鏈接:https://www.zhihu.com/question/34499262/answer/59415153
實例分析一:棧裏面的數據是共享的
int a=1;
int b=1;
編譯器預先處理int a =1;首先在棧中建立一個變量爲a的引用,而後去棧中查找有沒有字面值爲1的地址,沒有就開闢一個存放字面值爲1的地址。接着執行b=1;建立一個變量爲b的引用,因爲已經存在字面值爲1的地址了,因此b直接指向該地址。因此:出現了a,b同時指向1這個地址
特別注意:字面值的引用與對象的引用是不同的,假設兩個類對象的引用指向同一個對象,若是一個引用對象修改了這個類的內部狀態,那麼另外一個引用對象也會便可反映出這個變化;而字面值引用則不會,假設在寫上b=2,那麼b引用會從新去JVM棧中去尋找字面值爲2的地址,找不到則從新開闢一個地址來存儲2,而後b引用在指向它
public class test2 { public static void main(String[] args) { int a = 1; int b = 1; // 1.建立變量爲a的引用,在JVM棧中開闢字面值爲1的地址,a在指向它 // 2.建立變量爲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) { // 建立變量爲a的對象引用,new test()在堆中分配內存存儲該對象,a再指向堆區中該對象的地址 test a = new test(); // 建立變量值爲b的引用對象,指向a指向的堆區中地址 test b = a; System.out.println(a == b); b.num = 2; //這裏就屬於另外一個對象引用修改了該對象的內部狀態,致使a受影響了 System.out.println(a.num); // 2 若是是test b = new test()則輸出1,由於指向的不是同一個對象 // 這裏又在堆區中給test對象分配了內存 test c = new test(); System.out.println(a == c); } }
關於包裝類型數據:如Integer,Double,Float等將基本數據類型包裝起來的類,它們存在於堆區中。Java用new()來顯示的告訴編譯器要建立。以後將對包裝類型作一下整理,尤爲是地址指向
http://www.blogjava.net/hgc-ghc/archive/2013/05/02/398675.html
方法區也同堆同樣是被全部線程所共享的,它裏面存放着satic修飾的代碼和類信息,常量(final修飾)
線程私有,佔用內存小。
字節碼行號指示器,解釋器經過它來選取下一條執行的字節碼指令
不會有 OutOfMemoryError