jvm - 內存空間

前面提到了類加載到內存中,jvm會把內存劃分紅不一樣的數據區域,那加載的類是分配到哪裏呢?下圖是內存的各個區域,包括:方法區、堆、虛擬機棧、本地方法棧、程序計數器。
image.pngjava

方法區

方法區用於存儲已被虛擬機加載的類信息、常量、靜態變量、即時編譯器編譯後的代碼等數據。
類的加載中提到了類加載的五個階段。在加載階段,會將字節流所表明的靜態存儲結構轉化爲方法區的運行時數據結構,在準備階段,會將變量所使用的內存都將在方法區中進行分配。數據結構

程序計數器

來一個簡單的代碼,計算(1+2)*3並返回多線程

public int cal() {
    int a = 1;
    int b = 2;
    int c = 3;
    return (a + b) * c;
}

這段代碼在加載到虛擬機的時候,就變成了如下的字節碼,虛擬機執行的時候,就會一行行執行。
image.png
java是多線程的,在線程切換回來後,它須要知道原先的執行位置在哪裏。用來記錄這個執行位置的,就是程序計數器,爲了保證線程間的計數器相互不影響,這個內存區域是線程私有的。jvm

虛擬機棧

虛擬機棧也是線程私有的,生命週期與線程相同。每一個線程都有本身的虛擬機棧,若是這個線程執行了一個方法,就會建立一個棧幀,方法從調用直至執行完成的過程,就對應着一個棧幀在虛擬機棧中入棧到出棧的過程。
好比下面的例子,fun1調用fun2,fun2調用fun3,fun3建立Hello對象。this

public void fun1() {
    fun2();
}

public void fun2() {
    fun3();
}

public void fun3() {
    Hello hello = new Hello();
}

調用的時候,流程圖以下:
image.png
執行完成的時候,流程圖以下:
image.png
每個棧幀都包括了局部變量表、操做數棧、動態鏈接、方法返回地址和一些額外的附加信息。局部變量主要是存放方法參數以及方法內部定義的局部變量,操做數棧是一個後入先出棧,當方法剛剛開始執行的時候,這個方法的操做數棧是空的,在方法的執行過程當中,會有各類字節碼指令往操做數棧中寫入和提取內容,也就是出棧/入棧操做。
咱們經過上面(1+2)*3的例子,把方法區、程序計數器、虛擬機棧的協同工做理一下。首先經過javap查看它的字節碼,通過類加載器加載後,此時這個字節碼存在方法區中。stack表示棧深度是2,locals是本地變量的slot個數,args_size是入參的個數,默認是this。棧的深度、本地變量個數,入參個數,都是在編譯器決定的。
image.png
以下圖,指令的位置是方法區,局部變量和操做數棧的位置是虛擬機棧,程序計數器就在程序計數器(這個下面的圖就不在重複)。
當執行偏地址爲0的指令的時候,程序計數器爲0,局部變量第一個值是this,當前的指令就是方法區0:iconst_1,指令iconst_1就是把int常量值1進棧,這個1就到了虛擬機棧的操做數棧中,
image.png
當執行偏地址爲1的指令的時候,程序計數器爲1,把操做數棧的值賦值到局部變量,此時操做數棧清空了,局部變量多了一個1,這條指令執行完,就是對應上面int a=1的語句。
image.png
另外b,c兩個語句的賦值,對應着2,3,4,5指令,這邊再也不重複。執行完5後,以下圖所示:
image.png
執行6的時候,是執行iload_1,就是把第二個int型局部變量壓入棧頂,這裏的變量是1。
image.png
執行7的時候,是執行iload_2,就是把第三個int型局部變量壓入棧頂,這裏的變量是2。
image.png
執行8的時候,是iadd語句,指的是棧頂的兩個int型元素出棧,獲得結果後再壓入棧頂。
image.png
執行9的時候,把棧頂的元素3,賦值到第五個局部變量。
image.png
執行到11的時候,把第五個局部變量值壓入棧頂,執行到13的時候,把第四個局部變量值壓入棧頂,執行14的時候,棧頂的兩個int型元素出棧,相乘後的結果入棧,執行15的時候,從當前方法返回當前棧頂int型元素。這些與上面的相加差很少,就不在累述了。spa

堆內存區域的惟一目的就是存放對象實例,幾乎全部的對象實例都在這裏分配內存。好比上面的fun1調用fun2,fun2調用fun3,fun3建立Hello對象。fun3方法中建立對象時,就是在堆中建立的,而且把地址賦值給fun3的局部變量。Java堆中還能夠細分爲:新生代和老年代;新生代還細分爲Eden空間、From Survivor空間、To Survivor空間。
image.png線程

總結

總體流程以下,先把java文件編譯成class文件,經過類加載器加載到方法區。線程調用方法的時候,會建立一個棧幀,讀取方法區的字節碼執行指令,執行指令的時候,會把執行的位置記錄在程序計數器中,若是建立對象,會在堆內存中建立,方法執行完,這個棧幀就會出棧。
image.png3d

內存參數

  • -XX:PermSize:永久代內存容量。
  • -XX:MaxPermSize:永久代最大內存容量。
  • -Xss:棧內存容量。
  • -Xms:堆內存容量。
  • -Xmx:堆最大內存容量,一般和-Xms設置同樣,防止運行時擴容產生的影響。
  • -Xmn:新生代內存容量,老年代就是堆內存容量-新生代內存容量
  • -XX:SurvivorRatio=8:新生代還細分爲Eden空間、From Survivor空間、To Survivor空間,設置爲8表明Eden空間:From Survivor空間:To Survivor空間=8:1:1,好比新生代有10M,那Eden空間佔8M,From Survivor空間、To Survivor空間各佔1M。

image.png

相關文章
相關標籤/搜索