Jvm內存模型與GC垃圾回收

1. 總覽

在這裏插入圖片描述

程序計數器:

當前線程執行的字節碼的行號指示器,通過改變此指示器來選取下一個需要執行的字節碼指令。
特徵:在線程創建時創建、每個線程擁有一個、指向下一條指令的地址

方法區:

jdk1.8之後叫元空間,1.8之前叫永久代。是線程共享的
存儲:類信息、常量、靜態變量、方法字節碼

棧(線程)

是線程私有的,方法在執行時會創建一個棧幀(Stack Frame)用於存儲局部變量表、操作數棧、動態鏈接、方法出口等信息
方法從調用直至執行完成的過程,就對應着一個棧幀在虛擬機棧中入棧到出棧的過程。
局部變量表所需的內存空間在編譯期間完成分配,而且分配多大的局部變量空間是完全確定的,在方法運行期間不會改變其大小。出棧後空間釋放。

是線程共享的,存儲對象或數組。

本地方法棧:

存儲本地方法(native)的局部變量

程序計數器、(線程)棧、本地方法棧都是每一個線程獨有的(線程獨享)。

2. 詳細解釋

示例程序:

package com.tuling.jvm;

public class Math {

    public static final int initData = 666;
    public static User user = new User();

    public int compute(){//一個方法對應一塊站棧幀內存區域
        int a = 1;
        int b = 2;
        int c = (a + b)*10;
        return c;
    }

    public static void main(String[] args) {
        Math math = new Math();
        math.compute();
        System.out.println("test");
    }
}

對class文件使用命令javap -c Math.class > Math.txt生成jvm指令碼:在這裏插入圖片描述
部分指令解釋:
iconst_1 -> 將int類型常量1壓入操作數棧
istore_1 -> 在操作數棧中出棧(1),賦值給局部變量1

執行到4:iload_1,此時程序計數器的值就爲4
iload_1 -> 會將局部變量1加載進操作數棧
iadd -> 會把操作數(1和2)出棧,執行相加操作,然後再把結果(3)三壓入棧中
bipush 10 -> 把操作數(3)取出,與10做乘操作,再把結果(30)壓入操作數棧中
在這裏插入圖片描述

局部變量表:存放局部變量
操作數棧:存放臨時操作數
動態鏈接:將符號引用轉換爲直接引用
方法出口:記錄上一個方法調用該方法時執行的位置信息,保證方法完成後能回到上一個方法的合適位置繼續執行

方法區與堆:

1.方法區裏面的靜態類型變量如果有對象類型的,該變量是存儲的堆中該對象的內存地址(Math中的user指向堆中的user對象)
2.在堆中,每一個對象的對象頭裏面都有一個class的類型指針指向方法區中的類元信息

在這裏插入圖片描述
我們new出來的對象一般都放在堆的Eden區中,默認配置中,老年代佔堆內存的2/3,年輕代佔1/3,年輕代中Eden佔8/10,一旦Eden區中放滿,會進行minor GC:

minor GC:垃圾收集——把無效的無引用的對象回收掉,把存活的或者有引用的對象放入From區,這些對象的分代年齡加1;
Eden區下一次被放滿之後,又會觸發minor GC,收集Eden,同時如果From區不爲空,也會堆From區域進行回收,把存活下來的對象放入To區域,分代年齡加1;
再一次Eden區被放滿之後,又會觸發minor GC,對Eden、To區域做垃圾收集,把剩餘存活的對象放入From區 ,分代年齡加1…反覆運行,如果對象的分代年齡爲15之後還沒有被銷燬,該對象會被移入老年代。

當老年代中放滿之後,會進行full GC——對整個堆進行垃圾收集
在進行GC時,會進入STW

Stop-The-World機制簡稱STW,是在執行垃圾收集算法時,Java應用程序的其他所有線程都被掛起(除了垃圾收集幫助器之外)。

JVM性能調優就是要去減少GC的次數,減少GC的時間

垃圾收集結合實例:

package com.tuling.jvm;

import java.util.ArrayList;

public class HeapTest {

    byte[] a = new byte[1024*100]; //100KB

    public static void main(String[] args) throws InterruptedException {
        ArrayList<Object> heapTests = new ArrayList<>();
        while (true){
            heapTests.add(new HeapTest());
            Thread.sleep(10);
        }
    }
}

使用jdk自帶的jvisualvm,安裝visul GC插件,可以動態監視進程的情況:
在這裏插入圖片描述
文中原圖鏈接:https://www.processon.com/view/link/5e82edb3e4b0412013f10583

本文是根據公開課學習整理的筆記…

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章