1.JVM內存空間
JVM堆(Heap)= 新生代(Young) + 舊生代(Tenured)
分區作用:
新創建的對象通常先將其分配在新生代中,在新生代中經過若干次GC之後仍未釋放的對象,再將它移動到舊生代。爲了讓內存回收更高效(GC會暫停JVM中的應用),Sun JDK在1.2開始對堆採用了分代管理的方式。在分配對象遇到內存不足時,先對新生代進行GC(Young GC);當新生代GC之後仍無法滿足內存空間分配需求時, 纔會對整個堆空間以及方法區進行GC (Full GC)
相關參數:
-Xms -- 設置堆內存初始大小
-Xmx -- 設置堆內存最大值
-XX:MaxTenuringThreshold -- 設置對象在新生代中存活的次數
-XX:PretenureSizeThreshold -- 設置超過指定大小的大對象直接分配在舊生代中
注意點:當新生代設置得太小時,也可能引發大對象直接分配到舊生代中。
新生代(Young)= Eden區 + Survivor區
分區作用:
Eden區爲對象通常最初分配到的地方,Survivor區分爲S0和S1兩塊大小相等的區域。JVM進行Minor GC時,將Eden中還存活的對象拷貝到Survivor區中,還會將Survivor區中還存活的對象拷貝到Tenured區中。在這種GC模式下,JVM爲了提升GC效率, 將Survivor區分爲S0和S1,這樣就可以將對象回收和對象晉升分離開來。
相關參數:
-Xmn -- 設置新生代內存大小。
-XX:SurvivorRatio -- 設置Eden與Survivor空間的大小比例
注意點: 圖中Virtual部分表示可伸縮的內存空間,當用-Xms在指定堆的初始大小爲128m,通過-Xmx指定堆最大爲256m時,JVM會根據內存情況在128m與256m之間伸縮。爲了避免JVM進行這些伸縮消耗性能,對於能夠提供穩定內存空間的用作服務器的JVM,通常將-Xms和-Xmx設置爲相等。
方法區(Perm)
分區作用:
也被成爲持久代,用來存放JVM加載的類型信息。包括: 類型基本信息,常量池,字段信息,方法信息,類變量,指向ClassLoader的引用,Class類的引用,方法表等。方法區是全局共享的,在一定條件下也會被GC。
相關參數:
-XX:PermSize --設置Perm區的初始大小
-XX:MaxPermSize --設置Perm區的最大值
JVM方法棧(注意:不是分區)
作用:
JVM方法棧爲JVM線程私有內存,當方法運行完畢後,其對應的棧幀內存會自動釋放
相關參數:
-Xss --設置方法棧的最大值
TLAB:
JVM所佔用的主要內存都是從堆空間分配的,堆是所有線程共享的,因此在堆上分配內存需要加鎖,Sun JDK爲提升效率,會爲每個新建的線程在Eden上分配一塊獨立的空間由該線程獨享,這塊空間稱爲TLAB(Thread Local Allocation Buffer)。其大小由JVM根據運行情況計算得到,也可通過參數-XX:TLABWasteTargetPercent來設置TLAB可佔用的Eden空間的百分比,默認值爲1%。在TLAB上分配內存不需要加鎖,因此JVM在給線程中的對象分配內存時會盡量在TLAB上分配。如果對象過大或TLAB用完,則仍然在堆上進行分配。
2.Sun JDK GC收集器
跟蹤收集器簡介
複製(Copying)
標記-清除(Mark-Sweep)
<!--[if !supportLists]-->ü <!--[endif]-->優缺點:在空間中存活對象較多的情況下較爲高效,但由於該算法爲直接回收不存活對象所佔用的內存,因此會造成內存碎片。
標記-壓縮(Mark-Compact)
<!--[if !supportLists]-->ü <!--[endif]-->算法:標記階段與“標記-清除”算法相同,但在清除階段有所不同。在回收不存活對象所佔用的內存空間後,會將其他所有存活對象都往左端空閒的空間進行移動,並更新引用其對象指針。
<!--[if !supportLists]-->ü <!--[endif]-->過程:
<!--[if !supportLists]-->ü <!--[endif]-->優缺點:在“標記-清除”的基礎上還需要進行對象移動,成本相對較高,好處則是不產生內存碎片。
3. Sun JDK GC策略
圖4 Sun JDK中可用的GC方式
基於上一小節講解的跟蹤收集器算法,Sun JDK在新生代和老生代進行了不同的算法實現,形成了上圖中的GC方式分佈。本小節將具體介紹新生代和老生帶的GC策略及組合方式。
新生代 – 串行GC(Serial Copying)
算法:複製(Copy)
過程:
1. 掃描出新生代中存活的對象;
2. Minor GC將存活的對象複製到做爲To Space的S0/S1區;
3. 之前做爲To Space/From Spache的S0/S1區對換角色;
4. 經歷過幾次Minor GC仍然存活的對象,放入老生代。
新生代 – 並行回收GC(Parallel Scavenge)
算法:複製(Copy)
過程:在掃描和複製時均採用多線程方式進行(如下圖),並且並行回收GC爲大的新生代回收做了很多優化(可以自行擴展閱讀相關資料)。
新生代 – 並行GC(ParNew)
老生代 – 串行GC(Serial MSC)
老生代 – 並行GC(Parallel Mark Sweep、Parallel Compacting)
老生代 – 併發GC(CMS:Concurrent Mark-Sweep GC)
優缺點:如上圖,優點是只有在第一次標記和重新標記階段需要暫停整個應用,所以能夠做到影響應用響應時間很短。缺點是併發標記和併發收集階段CMS會與應用線程爭用CPU資源(用增量CMS模式可以緩解),並且容易產生內存碎片,free-list機制會導致Minor GC效率下降。
配置方法:通過-XX:UseConcMarkSweepGC來啓動老生代CMS GC;通過-XX:+UseCMSCompactAtFullCollection來啓動內存碎片整理功能(整理也會暫停應用)。
4.Sun JDK GC默認策略及組合策略
<!--[if !supportLists]-->ü <!--[endif]-->Clinet、Server模式默認GC策略
|
新生代GC方式 |
舊生代和持久代GC方式 |
Client |
串行GC |
串行GC |
Server |
並行回收GC |
Parallel Mark Sweep GC |
<!--[if !supportLists]-->ü <!--[endif]-->Sun JDK GC組合方式
|
新生代GC |
舊生代和持久代GC |
-XX:+UseSerialGC |
串行GC |
串行GC |
-XX:+UseParallelGC |
並行回收GC |
Parallel Mark Sweep GC |
-XX:+UseConcMarkSweepGC |
並行GC |
併發GC 當出現Concurrent Mode Failure時採用串行GC |
-XX:+UseParNewGC |
並行GC |
串行GC |
-XX:+UseParallelOldGC |
並行回收GC |
Parallel Mark Conpact |
-XX:+UseConcMarkSweepGC -XX:-UseParNewGC |
串行GC |
併發GC 當出現Concurrent Mode Failure或Promotion Failed時採用串行GC |
不支持的組合方式 |
1.-XX:+UseParNewGC -XX:+UseParallelOldGC 2.-XX:+UseParNewGC -XX:+UseSerialGC |