JVM
下圖是JDK的結構圖(來源於網絡)
不同版本JDK的JRE是不同的,JVM會將相同的字節碼文件解析成不同系統識別的0 1 二進制
JVM 的結構:
由以下代碼引入:
public class Demo {
public static final double PI = 3.14;
static Circle circle = new Circle();
public static void main(String[] args) {
Demo demo = new Demo();
int c = demo.calculate();
System.out.println(c);
}
public static int calculate() {
int a = 2;
int b = 3;
int c = (a + b) * 2;
return c;
}
}
class Circle{
private double radius;
public Circle() {
this(1.0);
}
public Circle(double radius){
this.radius=radius;
}
}
爲更加好理解棧幀,我們可以通過命令行查看Demo 的字節碼文件:
javap -c Demo.class > Demo.txt//-c 爲反彙編,可將字節碼文件編譯成更加容易理解的文件,並寫入到 Demo.txt文件中
Compiled from "Demo.java"
public class Demo {
public static final double PI;
static Circle circle;
public Demo();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
public static void main(java.lang.String[]);
Code:
0: new #2 // class Demo
3: dup
4: invokespecial #3 // Method "<init>":()V
7: astore_1
8: aload_1
9: pop
10: invokestatic #4 // Method calculate:()I
13: istore_2
14: getstatic #5 // Field java/lang/System.out:Ljava/io/PrintStream;
17: iload_2
18: invokevirtual #6 // Method java/io/PrintStream.println:(I)V
21: return
public static int calculate();
Code:
0: iconst_2
1: istore_0
2: iconst_3
3: istore_1
4: iload_0
5: iload_1
6: iadd
7: iconst_2
8: imul
9: istore_2
10: iload_2
11: ireturn
static {};
Code:
0: new #7 // class Circle
3: dup
4: invokespecial #8 // Method Circle."<init>":()V
7: putstatic #9 // Field circle:LCircle;
10: return
}
JVM指令手冊可以私聊我發給你們(免費)
堆的結構:
說明:分代的原因在於提高對象分配內存和垃圾回收的效率,新的對象會放在伊甸園區,當伊甸園區滿了之後會由執行引擎進行垃圾回收,即young GC或稱minor GC,存活的對象放入S1中,當伊甸園區再次滿的時候會再次進行minor GC,這次收集的是伊甸園區和S1中的垃圾,將兩個區中都存活的對象再放入S2中,而原先在S1中的對象的分代年齡+1,當伊甸園區再次滿的時候再將伊甸園區和S2中存活的對象放入S1中,原先在S2中的對象的分代年齡+1;當一個對象的分代年齡到達15的時候,會被放入老年代,當老年代放滿的時候會執行full GC,系統消耗非常高,應儘量避免full GC,一天、一週、一個月進行一次爲正常,還有很多規則使對象直接進入老年代,例如其中之一:當Eden中存活的對象大小大於S1的50%時,就直接進入老年代。
JVM調優基礎
當輸入java -version時
會出現client或者server兩種不同的機制,client機制更多的基於桌面級應用,分配的空間相對比server 少,但是server機制會造成空間浪費,這兩種機制可以在jre中修改。
可以進行JVM調優的點:
- 選擇client還是server機制
- 對堆的大小的分配,手動調參數
例如:-Xms:初始化堆的大小
-Xmx:最大堆大小
-XX:New Size:n:設置年輕代的大小 - 垃圾收集器的選擇
JVM中的垃圾收集器:
連線表示收集器可以配合使用
serial收集器:唯一一個次收集器,是一個串行收集器,STW(stop the world):收集時暫停整個線程。(圖片來自網絡)
注意
新生代使用的是複製算法,而老年代使用的是標記-整理算法
parNew收集器:並行收集器,是CMS默認配合的收集器,多核CPU可以顯示出能力,單核和serial效果一樣。(圖片來自網絡)
parallel :提高吞吐率
系統吞吐率=代碼執行時間/(代碼執行時間+垃圾收集時間)
CMS收集器:垃圾收集和用戶線程併發執行
G1:新生代和老年代的垃圾都可以回收
常用的垃圾回收算法
1.引用計數:
一個對象有一個引用就加1,少一個引用就減1,如果爲0就回收,缺點是無法解決循環引用的問題
2.複製算法:
劃分爲兩個相等的區域,只複製正在處理的對象,複製過去可以有序的整理,沒有空間碎片,缺點:需要兩倍空間
3.標記-清除算法:
第一階段從引用的根節點開始標記所有被引用的對象,第二階段遍歷整個堆,將爲標記的對象清除。此算法需要暫停整個應用,同時,會產生內存碎片。
4.標記-整理算法:
此算法是對標記-清除的優化,使用標記-清除方法清除後,再將存活的對象壓入到堆中的一塊區域,按順序排好,解決了標記-清除的內存碎片問題和賦值的空間問題。
以上是自己對JVM所學整理的筆記,不完整,今後會逐步完善!
加油!