其實這個問題很是簡單,JVM在運行咱們寫好的代碼時,他是必須使用多塊內存空間的,不一樣的內存空間用來放不一樣的數據,而後配合咱們寫的代碼流程,才能讓咱們的系統運行起來。java
舉個最簡單的例子,好比我們如今知道了JVM會加載類到內存裏來供後續運行,那麼我問問你們,這些類加載到內存之後,放到哪兒去了呢?想過這個問題嗎?安全
因此JVM裏就必須有一塊內存區域,用來存放咱們寫的那些類。bash
包括咱們定義的成員變量,類變量,方法,局部變量等等,都在jvm內存中對應着一塊內存來記錄存儲。數據結構
在JDK1.8以前的版本里,表明JVM的一塊區域。在1.8版本之後,這塊區域的名字改了,叫作「Matespace」,能夠認爲是「元數據空間」這樣的意思,固然這裏主要存放的仍是咱們本身寫的各類類的相關信息。多線程
舉個例子。有以下兩個類,User1類沒有成員變量,而User2類有一個realName的類變量。併發
public class User1 {
private String userName = "wangwu";
}
public class User2 {
private static String realName = "zhangsan";
private String userName = "lisi";
}
複製代碼
這兩個類被加載到JVM,就會存放在這個方法區裏面(類的全部類變量都會被賦值)。以下圖jvm
咱們知道,被加載到jvm的類對象是咱們寫的.java文件被編譯以後的.class文件。ui
在編譯事後會將咱們的代碼編譯成計算機能讀懂的字節碼。而這個.calss文件就是,就是咱們代碼編譯好的字節碼了。spa
加載到內存之後,字節碼執行引擎就開始工做了。去執行咱們編譯出來的代碼指令,此時問題來了,咱們是否是須要一塊內存空間來記錄咱們字節碼執行引擎目前執行到了哪行代碼?這一塊特殊的內存區域就是「程序計數器」,就是用來記錄當前執行的字節碼指令的位置。操作系統
注:多線程環境併發執行的狀況下,計算器CPU是必定的,在CPU從線程1切換到線程2,再切換回線程1的時候,是否是要知道線程1執行到哪一步了,這就是程序計數器的做用。所以,當線程再次上下文切換到以前的代碼時,就須要一個專門記錄當前線程執行到了哪一條字節碼。因此,每個線程都有這本身的程序計數器。
當線程執行到某個方法的時候,若是這個方法有局部變量,那麼就須要一塊區域來存放局部變量的數據信息。這個區域就叫作java虛擬機棧。
每個線程都有一個本身的java虛擬機棧,好比說當執行main方法的時候就會有一個main線程,用來存放main方法中定義的局部變量
public class TestController {
public static void main(String[] args) {
int i = 1;
User1 user1=new User1();
user1.setUserName("sss");
}
}
複製代碼
好比上面的main()方法中,其實就有一個"user1"的局部變量,他是引用一個User1的實例對象的,還有一個"i"的局部變量. 以下圖:
既然是棧,那就遵循後進先出的原則。當方法執行完畢之後,這個棧楨就會出棧,裏面的局部變量信息就會從內存刪除。因此局部變量是線程安全的。由於只有當前線程能獲取到這個值。
Q:爲何要用後進先出的數據結構?
A:假設a方法中調用b方法,此時a方法的棧楨先入棧,b方法的棧楨後入棧。當b方法執行完畢後,b方法的棧楨先出棧,繼續執行a方法,而後a方法的棧幀再出棧。因此使用一個後進先出的棧結構是很是完美的。
仍是上面代碼,當main線程執行main()方法的時候,首先在堆內存中實例化User1對象,而後在局部變量中建立user1,user1存的是實例化User1對象的內存地址。而後執行Student對象的getName()方法。
以下圖:
其實在JDK的不少底層代碼API中,好比NIO。
若是你去看源碼會發現不少地方的代碼不是java寫的,而是走的native方法去調用本地操做系統裏面的一些方法,可能調用的都是c語言寫的方法。
好比說:
public native int hashCode();
public final native boolean compareAndSwapInt(Object paramObject, long paramLong, int paramInt1, int paramInt2);
複製代碼
在調用這種native方法的時候,就會有線程對應的本地方法棧,這個其實相似於java虛擬機棧。也是存放各類native方法的局部變量表之類的信息。
還有一塊區域,是否是jvm的,經過NIO中的allocateDirect這種API,能夠在jva堆外分配內存空間,而後經過java虛擬機棧裏的DirectByteBuffer來引用和操做堆外內存空間。