JVM基礎知識

       JVM是Java Virtual Machine(Java虛擬機)的縮寫,JVM是一種用於計算設備的規範,它是一個虛構出來的計算機,是經過在實際的計算機上仿真模擬各類計算機功能來實現的。html

JVM內存組成結構java

一、本地方法棧算法

用於支持native方法的執行,存儲了每一個native方法調用的狀態jvm

二、方法區性能

存放了要加載的類信息、靜態變量、final類型的常量、屬性和方法信息。JVM用持久代(Permanet Generation)來存放方法區,可經過-XX:PermSize和-XX:MaxPermSize來指定最小值和最大值測試

三、JAVA棧spa

       在jvm中棧用來存儲一些對象的引用(例如方法引用)、基本數據類型(boolean、byte、char、short、int、float、long、double)。它的存儲比堆快得多,只比CPU裏的寄存器慢。每一個線程都有本身的Stack Space(棧),在JDK5.0以前每一個線程棧大小爲256k,JDK5.0以後改成1M。線程

*使用遞歸時若是深度過深很容易致使棧溢出(StackOverflowError),此時能夠經過設置棧大小來處理(-Xss:如-Xss128k)htm

測試用例:對象

public class StackTest{

    private static int count=0;

    public static void add(long a,long b){
        count++;
        add(a,b);
    }
    public static void main(String args[]){
        try{
            add(0L,0L);
        }catch(Throwable e){
            System.out.println("深度爲: "+count);
            System.exit(0);
            e.printStackTrace();
        }
    }
}

-Xss分別設置成128k和256k結果分別爲:

深度爲: 8964(128k)

深度爲: 17700 (256K)

四、JAVA堆

一:新生代:主要是用來存放新生的對象。通常佔據堆的1/3空間。因爲頻繁建立對象,因此新生代會頻繁觸發MinorGC進行垃圾回收。

         新生代又分爲 Eden區、ServivorFrom、ServivorTo三個區。

         Eden區:Java新對象的出生地(若是新建立的對象佔用內存很大,則直接分配到老年代)。當Eden區內存不夠的時候就會觸發MinorGC,對新生代區進行一次垃圾回收。

         ServivorTo:保留了一次MinorGC過程當中的倖存者。

         ServivorFrom:上一次GC的倖存者,做爲這一次GC的被掃描者。

         MinorGC的過程:MinorGC採用複製算法。首先,把Eden和ServivorFrom區域中存活的對象複製到ServicorTo區域(若是有對象的年齡以及達到了老年的標準,則賦值到老年代區),同時把這些對象的年齡+1(若是ServicorTo不夠位置了就放到老年區);而後,清空Eden和ServicorFrom中的對象;最後,ServicorTo和ServicorFrom互換,原ServicorTo成爲下一次GC時的ServicorFrom區。

 

二:老年代:主要存放應用程序中生命週期長的內存對象。

    老年代的對象比較穩定,因此MajorGC不會頻繁執行。在進行MajorGC前通常都先進行了一次MinorGC,使得有新生代的對象晉身入老年代,致使空間不夠用時才觸發。當沒法找到足夠大的連續空間分配給新建立的較大對象時也會提早觸發一次MajorGC進行垃圾回收騰出空間。

    MajorGC採用標記—清除算法:首先掃描一次全部老年代,標記出存活的對象,而後回收沒有標記的對象。MajorGC的耗時比較長,由於要掃描再回收。MajorGC會產生內存碎片,爲了減小內存損耗,咱們通常須要進行合併或者標記出來方便下次直接分配。

     當老年代也滿了裝不下的時候,就會拋出OOM(Out of Memory)異常。

 

 三:永久代

    指內存的永久保存區域,主要存放Class和Meta(元數據)的信息,Class在被加載的時候被放入永久區域. 它和和存放實例的區域不一樣,GC不會在主程序運行期對永久區域進行清理。因此這也致使了永久代的區域會隨着加載的Class的增多而脹滿,最終拋出OOM異常。

    在Java8中,永久代已經被移除,被一個稱爲「元數據區」(元空間)的區域所取代。

    元空間的本質和永久代相似,都是對JVM規範中方法區的實現。不過元空間與永久代之間最大的區別在於:元空間並不在虛擬機中,而是使用本地內存。所以,默認狀況下,元空間的大小僅受本地內存限制。類的元數據放入 native memory, 字符串池和類的靜態變量放入java堆中. 這樣能夠加載多少類的元數據就再也不由MaxPermSize控制, 而由系統的實際可用空間來控制.

    採用元空間而不用永久代的幾點緣由:(參考:http://www.cnblogs.com/paddix/p/5309550.html)

  一、爲了解決永久代的OOM問題,元數據和class對象存在永久代中,容易出現性能問題和內存溢出。

  二、類及方法的信息等比較難肯定其大小,所以對於永久代的大小指定比較困難,過小容易出現永久代溢出,太大則容易致使老年代溢出(由於堆空間有限,此消彼長)。

  三、永久代會爲 GC 帶來沒必要要的複雜度,而且回收效率偏低。

*堆內存設置

-Xmx:最大堆內存,如:-Xmx512m  (默認是物理內存的1/4)

-Xms:初始時堆內存,如:-Xms256m  (默認是物理內存的1/64)

-XX:MaxNewSize:最大年輕區內存

-XX:NewSize:初始時年輕區內存.一般爲 Xmx 的 1/3 或 1/4。新生代 = Eden + 2 個 Survivor 空間。實際可用空間爲 = Eden + 1 個 Survivor,即 90%

-XX:MaxPermSize:最大持久帶內存

-XX:PermSize:初始時持久帶內存

-XX:+PrintGCDetails。打印 GC 信息

 -XX:NewRatio 新生代與老年代的比例,如 –XX:NewRatio=2,則新生代佔整個堆空間的1/3,老年代佔2/3

 -XX:SurvivorRatio 新生代中 Eden 與 Survivor 的比值。默認值爲 8。即 Eden 佔新生代空間的 8/10,另外兩個 Survivor 各佔 1/10

 

JVM GC觸發

1.Minor GC

從年輕代空間(包括 Eden 和 Survivor 區域)回收內存被稱爲 Minor GC(好比當 Eden 區滿了)

2.Major GC 

是清理老年代(通常老年代空間不足時觸發)。

3.Full GC 

是清理整個堆空間—包括年輕代和老年代

Full GC觸發條件:

(1)調用System.gc時,系統建議執行Full GC,可是沒必要然執行

(2)老年代空間不足

(3)方法區空間不足

(4)經過Minor GC後進入老年代的平均大小大於老年代的可用內存

(5)由Eden區、From Space區向To Space區複製時,對象大小大於To Space可用內存,則把該對象轉存到老年代,且老年代的可用內存小於該對象大小  

相關文章
相關標籤/搜索