天天看點

jvm學習之jvm基礎

java虛拟機是一台執行java位元組碼的虛拟計算機,他獨立的運作機制,無論什麼語言,隻要最終編譯成jvm識别的位元組碼,那麼他就可以在jvm上運作。立足于jvm可以實作各種各樣的跨平台。以前斷斷續續學過jvm,後來發現長時間不看還是容易忘的,還是整理一下比較好。jvm内容比較多,涉及底層彙編也比較枯燥,但是學習他對于我們了解一些關鍵問題是很有幫助的,今天先從基礎的也比較重要的記憶體配置設定開始。

一.記憶體模型簡述

先看幾個圖,這幾個是我照着《實戰java虛拟機》中畫的,感覺這幾個圖不錯,另外再給大家推薦個免費畫圖的線上網站:www.processon.com;畫UML神馬的特别友善 。

jvm學習之jvm基礎

了解jvm的童鞋對這幾個圖應該不陌生,我這裡在明确一下:

類加載子系統:負責從檔案系統或則網絡中加載Class資訊

方法區:存放加載後的類資訊,運作時常量池資訊(字元串常量,數字常量)

java堆:java堆在虛拟機啟動的時候建立,幾乎所有的java對象執行個體都存放其中,堆空間是所有線程共享的。

直接記憶體:其在java堆外,直接向系統申請的記憶體空間,通路速度優于java堆。

垃圾回收系統:可以對方法區,java堆和直接記憶體進行回收,其中,java堆是垃圾回收的重點。

java棧:每一個虛拟機線程都有一個私有的棧,一個線程的java棧線上程建立的時候建立,java棧儲存幀資訊。

本地方法棧:與java棧類似,但是java棧用于java方法的調用,而本地方法用于本地方法的調用。(C編寫)

PC:每個線程私有的空間,指向目前正在被執行的指令。

執行引擎:執行虛拟機位元組碼。

這裡面最重要的莫過于堆和java棧了,java的記憶體的配置設定和調用和這兩個有着密切的聯系。

jvm學習之jvm基礎

對于堆,如上面的圖畫的,分為新生代和老年代,新生代又分為幾個部分,這個我覺得可能是叫法不一樣,有些書把s0,s1也寫成from to。對象首先配置設定在eden區,在一次新生代回收時,如果對象還存活,就進入s0,或s1區,每一次新生代回收,對象加入過存活,年齡就加一,達到一定條件,就會認為是老年對象,進入老年代。

java棧

jvm學習之jvm基礎

java棧是和線程密切相關的,線程的基本行為是函數調用,java棧主要内容為棧幀,每一次函數調用都會有一個對應的棧幀壓人java棧,調用結束,跳出棧。一個棧幀中,包含局部變量表,操作數棧,幀資料區。

局部變量表隻在目前調用的函數有效,棧幀銷毀,局部變量表也銷毀,需要注意的是,棧幀中的局部變量表的槽位是可以複用的,如果一個局部變量過了其作用域,那麼在其後申明的局部變量就會占用他的槽位, 要記住隻要被局部變量表直接或間接引用的對象是不會被回收的。這個對于垃圾回收的了解是很重要的,下面我舉個例子,看代碼

public class VarGc {

public void varGc1(){
    byte[] a = new byte[5*1024*1024];
    System.gc();
}
public void varGc2(){
    byte[] a = new byte[5*1024*1024];
    a = null;
    System.gc();
}
public void varGc3(){
    {
        byte[] a = new byte[5*1024*1024];
    }
    System.gc();
}
public void varGc4(){
    {
        byte[] a = new byte[5*1024*1024];
    }
    int c = 5;
    System.gc();
}
public void varGc5(){
    varGc1();
    System.gc();
}
public static void main(String[] args) {
    VarGc varGc = new VarGc();
    varGc.varGc4();

}
           

}

這裡采用虛拟機參數:-XX:+PrintGC
測試4的結果:
[GC 6308K->656K(54272K), 0.0029735 secs]
           

上面這段程式很好了解,下面我們分析下他的垃圾回收過程:

對于函數1:數組被a引用,無法進行回收

函數2:數組失去強引用,可以回收

函數3:雖然a離開了作用域,但是a還存在于局部變量表中,不能回收

函數4:變量c複用了變量a的字變量a銷毀,可以回收

函數5:調用函數1後,他的棧幀銷毀,包含棧幀所有的局部變量都銷毀,可以回收

操作數棧:儲存計算過程的中間結果

幀資料區:儲存通路常量池的指針

方法區

有的書上也叫永久區,類的字段,方法,常量池都儲存在這,如果系統定義太多的類,就會導緻方法區溢出。

二.jvm常用參數

1.垃圾回收日志

-XX:PrintGC

:遇到垃圾回收,就會列印日志,比如上面我們的例子

[GC 6308K->656K(54272K), 0.0029735 secs]

GC前堆空間使用量約6M,GC後,堆空間使用量656k,目前可用的堆空間一共約54M

-XX:+PrintGCDetail: 這個指令會列印出詳細的GC日志,堆各個區的變化等

2.類加載解除安裝:

-verbose:class :跟蹤類加載或解除安裝

也可以用:-XX:+TraceClassLoading -XX:+TraceClassUnloading

這個一般檢視動态代理生成類的時候就可以用

3.配置堆:

-Xms:指定初始堆的大小

-Xmx:最大堆的大小

可以知道,目前總記憶體不小于-Xms,目前總記憶體總是在-Xms和-Xmx之間,從-Xms開始根據需要增長

-Xmn:設定新生代的大小

-XX:SurvivorRatio:設定eden空間與from/to空間的比例關系

-XX:NewRatio:設定老年代與新生代的比例

4.方法區配置:

-XX:PermSize:初始方法區大小

-XX:MaxPermSize:最大方法區大小

5.棧配置

-Xss:指定棧的大小

繼續閱讀