Java基礎(chǔ)(5)—垃圾回收機(jī)制 GC

image.png

垃圾回收機(jī)制(GC)

簡(jiǎn)介:

JVM的垃圾回收機(jī)制稱(chēng)為GC,眾所周知化戳,java語(yǔ)言不需要像c++那樣需要自己申請(qǐng)內(nèi)存涧至,自己釋放內(nèi)存搀别,它可以自動(dòng)回收可以釋放的內(nèi)存資源急侥。如果不進(jìn)行垃圾回收,內(nèi)存遲早都會(huì)被消耗空姚垃,因?yàn)槲覀冊(cè)诓粩嗟姆峙鋬?nèi)存空間而不進(jìn)行回收念链。除非內(nèi)存無(wú)限大,我們可以任性的分配而不回收积糯,但是事實(shí)并非如此掂墓。所以,垃圾回收是必須的看成。

JVM內(nèi)存運(yùn)行時(shí)數(shù)據(jù)區(qū):

結(jié)構(gòu)圖:

image.png

基礎(chǔ)知識(shí):

堆(heap):

最大的君编,最重要的一塊區(qū)域,稱(chēng)為邏輯堆川慌,主要用來(lái)存放對(duì)象實(shí)例與數(shù)組吃嘿,對(duì)于所有的線程來(lái)說(shuō)他是全局共享的,對(duì)于Heap堆區(qū)是動(dòng)態(tài)分配內(nèi)存的梦重,所以空間大小和生命周期都不是明確的兑燥,而GC的主要作用就是自動(dòng)釋放邏輯堆里實(shí)例對(duì)象所占的內(nèi)存,而在邏輯堆中還分為新生代與老年代琴拧,用來(lái)區(qū)分對(duì)象的存活時(shí)間降瞳,在新生代中還被細(xì)致的分為 Eden SurvivorFrom以及SurvivorTo這三部分。

方法區(qū)(Method Area):

主要存儲(chǔ)(類(lèi)加載器)ClassLoader加載的類(lèi)信息艾蓝,可理解為已經(jīng)編譯好的代碼儲(chǔ)存區(qū)力崇,所以存儲(chǔ)包括類(lèi)的元數(shù)據(jù)斗塘、常量池赢织、字段、靜態(tài)變量與方法內(nèi)的局部變量以及編譯好的字節(jié)碼等等馍盟。在Hotspot里將它稱(chēng)之為永生代于置。

棧(stack):

全稱(chēng)為虛擬機(jī)棧,主要存儲(chǔ)基本數(shù)據(jù)類(lèi)型,以及對(duì)象的引用八毯,私有線程搓侄。在每一個(gè)對(duì)象被創(chuàng)建的時(shí)候,在堆棧區(qū)都有一個(gè)對(duì)他的引用话速。

Object obj = new Object();

左邊的Object obj 等于在堆棧區(qū)申請(qǐng)了一個(gè)內(nèi)存讶踪,也就是對(duì)類(lèi)的引用,而 new Object()則是生成了一個(gè)實(shí)例泊交,= 則是將對(duì)象的內(nèi)容可通過(guò)obj進(jìn)行訪問(wèn)乳讥,在Java里都是通過(guò)引用來(lái)操縱對(duì)象。

pc寄存器(PC Register):

在多線程中廓俭,系統(tǒng)需要給每一個(gè)線程分配一個(gè)編號(hào)云石,這個(gè)時(shí)候才會(huì)需要到寄存器。

四大引用狀態(tài)(JDK 1.2之后):

1.強(qiáng)引用:

代碼中普遍存在的類(lèi)似"Object obj = new Object()"這類(lèi)的引用研乒,只要強(qiáng)引用還存在汹忠,除非程序員手動(dòng)代碼解除強(qiáng)引用,釋放資源雹熬。否值宽菜,垃圾收集器永遠(yuǎn)不會(huì)回收掉被引用的對(duì)象。

2.軟引用:

描述有些還有用但并非必需的對(duì)象竿报。在系統(tǒng)將要發(fā)生內(nèi)存溢出異常之前赋焕,將會(huì)把這些對(duì)象列進(jìn)回收范圍進(jìn)行二次回收。如果這次回收還沒(méi)有足夠的內(nèi)存仰楚,才會(huì)拋出內(nèi)存溢出異常隆判。Java中的類(lèi)SoftReference表示軟引用。

3.弱引用:

描述非必需對(duì)象僧界。被弱引用關(guān)聯(lián)的對(duì)象只能生存到下一次垃圾回收之前侨嘀,垃圾收集器工作之后,無(wú)論當(dāng)前內(nèi)存是否足夠捂襟,都會(huì)回收掉只被弱引用關(guān)聯(lián)的對(duì)象咬腕。Java中的類(lèi)WeakReference表示弱引用。

4.虛引用:

這個(gè)引用存在的唯一目的就是在這個(gè)對(duì)象被收集器回收時(shí)收到一個(gè)系統(tǒng)通知葬荷,被虛引用關(guān)聯(lián)的對(duì)象涨共,和其生存時(shí)間完全沒(méi)關(guān)系。Java中的類(lèi)PhantomReference表示虛引用宠漩。

兩大查找回收對(duì)象法:

1.引用計(jì)數(shù)法:

給對(duì)象中添加一個(gè)引用計(jì)數(shù)器举反,每當(dāng)一個(gè)地方引用這個(gè)對(duì)象時(shí),計(jì)數(shù)器值+1扒吁;當(dāng)引用失效時(shí)火鼻,計(jì)數(shù)器值-1。任何時(shí)刻計(jì)數(shù)值為0的對(duì)象就是不可能再被使用的。這種算法使用場(chǎng)景很多魁索,但是融撞,Java中卻沒(méi)有使用這種算法,因?yàn)檫@種算法很難解決對(duì)象之間相互引用的情況粗蔚。

/**
* 虛擬機(jī)參數(shù):-verbose:gc
*/
public class ReferenceCountingGC
{
  private Object instance = null;
  private static final int _1MB = 1024 * 1024;    
  /** 這個(gè)成員屬性唯一的作用就是占用一點(diǎn)內(nèi)存 */
  private byte[] bigSize = new byte[2 * _1MB];    
  public static void main(String[] args)
  {
      ReferenceCountingGC objectA = new ReferenceCountingGC();
      ReferenceCountingGC objectB = new ReferenceCountingGC();
      objectA.instance = objectB;
      objectB.instance = objectA;
      objectA = null;
      objectB = null;
      
      System.gc();
  }
}
/*
運(yùn)行結(jié)果:
[GC 4417K->288K(61440K), 0.0013498 secs]
[Full GC 288K->194K(61440K), 0.0094790 secs]
*/

兩個(gè)對(duì)象相互引用著尝偎,但是虛擬機(jī)還是把這兩個(gè)對(duì)象回收掉了,這也說(shuō)明虛擬機(jī)并不是通過(guò)引用計(jì)數(shù)法來(lái)判定對(duì)象是否存活的鹏控。

2.可達(dá)性分析法:

通過(guò)一系列稱(chēng)為“GC Roots”的對(duì)象作為起始點(diǎn)冬念,從這些節(jié)點(diǎn)向下搜索,搜索所走過(guò)的路徑稱(chēng)為引用鏈牧挣,當(dāng)一個(gè)對(duì)象到GC Roots沒(méi)有任何引用鏈(即GC Roots到對(duì)象不可達(dá))時(shí)急前,則證明此對(duì)象是不可用的。

GC Roots的對(duì)象包括下面幾種:
1.虛擬機(jī)棧(棧幀中的局部變量區(qū)瀑构,也叫局部變量表)中的引用對(duì)象裆针。
2.方法區(qū)中的類(lèi)靜態(tài)屬性引用的對(duì)象。
3.方法區(qū)中常量引用的對(duì)象寺晌。
4.本地方法棧中JNI(Native方法)引用的對(duì)象世吨。

image.png

由圖可知,obj8呻征、obj9耘婚、obj10都沒(méi)有到GCRoots對(duì)象的引用鏈,即便obj9和obj10之間有引用鏈陆赋,他們還是會(huì)被當(dāng)成垃圾處理沐祷,可以進(jìn)行回收。

注意:

對(duì)于可達(dá)性分析算法而言攒岛,未到達(dá)的對(duì)象并非是“非死不可”的赖临,若要宣判一個(gè)對(duì)象死亡,至少需要經(jīng)歷兩次標(biāo)記階段灾锯。

1.如果對(duì)象在進(jìn)行可達(dá)性分析后發(fā)現(xiàn)沒(méi)有與GCRoots相連的引用鏈兢榨,則該對(duì)象被第一次標(biāo)記并進(jìn)行一次篩選,篩選條件為是否有必要執(zhí)行該對(duì)象的finalize方法顺饮,若對(duì)象沒(méi)有覆蓋finalize方法或者該finalize方法是否已經(jīng)被虛擬機(jī)執(zhí)行過(guò)了吵聪,則均視作不必要執(zhí)行該對(duì)象的finalize方法,即該對(duì)象將會(huì)被回收兼雄。反之吟逝,若對(duì)象覆蓋了finalize方法并且該finalize方法并沒(méi)有被執(zhí)行過(guò),那么君旦,這個(gè)對(duì)象會(huì)被放置在一個(gè)叫F-Queue的隊(duì)列中澎办,之后會(huì)由虛擬機(jī)自動(dòng)建立的嘲碱、優(yōu)先級(jí)低的Finalizer線程去執(zhí)行金砍,而虛擬機(jī)不必要等待該線程執(zhí)行結(jié)束局蚀,即虛擬機(jī)只負(fù)責(zé)建立線程,其他的事情交給此線程去處理恕稠。

2.對(duì)F-Queue中對(duì)象進(jìn)行第二次標(biāo)記琅绅,如果對(duì)象在finalize方法中拯救了自己,即關(guān)聯(lián)上了GCRoots引用鏈鹅巍,如把this關(guān)鍵字賦值給其他變量千扶,那么在第二次標(biāo)記的時(shí)候該對(duì)象將從“即將回收”的集合中移除,如果對(duì)象還是沒(méi)有拯救自己骆捧,那就會(huì)被回收澎羞。

如下代碼演示了一個(gè)對(duì)象如何在finalize方法中拯救了自己,然而敛苇,它只能拯救自己一次妆绞,第二次就被回收了。

/*
* 此代碼演示了兩點(diǎn):
* 1.對(duì)象可以再被GC時(shí)自我拯救
* 2.這種自救的機(jī)會(huì)只有一次枫攀,因?yàn)橐粋€(gè)對(duì)象的finalize()方法最多只會(huì)被系統(tǒng)自動(dòng)調(diào)用一次
* */
public class FinalizeEscapeGC {    
  public String name;
  public static FinalizeEscapeGC SAVE_HOOK = null;
  public FinalizeEscapeGC(String name) {
      this.name = name;
  }

  public void isAlive() {
      System.out.println("我還活著括饶。)");
  }
  
  @Override
  protected void finalize() throws Throwable {
      super.finalize();
      System.out.println("finalize method 執(zhí)行");
      System.out.println(this);
      FinalizeEscapeGC.SAVE_HOOK = this;
  }

  @Override
  public String toString() {
      return name;
  }

  public static void main(String[] args) throws InterruptedException {
      SAVE_HOOK = new FinalizeEscapeGC("jimyoungwei");
      System.out.println(SAVE_HOOK);
      // 對(duì)象第一次拯救自己
      SAVE_HOOK = null;
      System.out.println(SAVE_HOOK);
      System.gc();
      // 因?yàn)閒inalize方法優(yōu)先級(jí)很低,所以暫停0.5秒以等待它
      Thread.sleep(500);
      if (SAVE_HOOK != null) {
          SAVE_HOOK.isAlive();
      } else {
          System.out.println("我已消亡来涨。");
      }

      // 下面這段代碼與上面的完全相同,但是這一次自救卻失敗了
      // 一個(gè)對(duì)象的finalize方法只會(huì)被調(diào)用一次
      SAVE_HOOK = null;
      System.gc();
      // 因?yàn)閒inalize方法優(yōu)先級(jí)很低图焰,所以暫停0.5秒以等待它
      Thread.sleep(500);
      if (SAVE_HOOK != null) {
          SAVE_HOOK.isAlive();
      } else {
          System.out.println("我已消亡。");
      }
  }
}
/*
運(yùn)行結(jié)果:
jimyoungwei
null
finalize method 執(zhí)行
jimyoungwei
我還活著蹦掐。
我已消亡技羔。
*/

對(duì)象的finalize方法最多被虛擬機(jī)調(diào)用一次,一個(gè)堆對(duì)象的this(放在局部變量表中的第一項(xiàng))引用會(huì)永遠(yuǎn)存在卧抗,在方法體內(nèi)可以將this引用賦值給其他變量堕阔,這樣堆中對(duì)象就可以被其他變量所引用,即不會(huì)被回收颗味。

四大垃圾收集算法:

1.標(biāo)記-消除(Mark-Sweep)算法:

最基礎(chǔ)的算法超陆,分為“標(biāo)記”和“清除”兩個(gè)階段:首先標(biāo)記出所有需要回收的對(duì)象,標(biāo)記完成后統(tǒng)一回收所有被標(biāo)記的對(duì)象浦马。

不足:主要體現(xiàn)在效率和空間:從效率的角度講时呀,標(biāo)記和清除兩個(gè)過(guò)程的效率都不高;從空間的角度講晶默,標(biāo)記清除后會(huì)產(chǎn)生大量不連續(xù)的內(nèi)存碎片谨娜, 內(nèi)存碎片太多可能會(huì)導(dǎo)致以后程序運(yùn)行過(guò)程中在需要分配較大對(duì)象時(shí),無(wú)法找到足夠的連續(xù)內(nèi)存而不得不提前觸發(fā)一次垃圾收集動(dòng)作磺陡。

標(biāo)記-清除算法執(zhí)行過(guò)程如圖:


image.png

2.復(fù)制(Copying)算法:

復(fù)制算法是為了解決效率問(wèn)題而出現(xiàn)的趴梢,它將可用的內(nèi)存分為兩塊漠畜,每次只用其中一塊,當(dāng)這一塊內(nèi)存用完了坞靶,就將還存活著的對(duì)象復(fù)制到另外一塊上面憔狞,然后再把已經(jīng)使用過(guò)的內(nèi)存空間一次性清理掉。這樣每次只需要對(duì)整個(gè)半?yún)^(qū)進(jìn)行內(nèi)存回收彰阴,內(nèi)存分配時(shí)也不需要考慮內(nèi)存碎片等復(fù)雜情況瘾敢,只需要移動(dòng)指針,按照順序分配即可尿这。

不足:內(nèi)存縮小為了原來(lái)的一半簇抵。

復(fù)制算法執(zhí)行過(guò)程如圖:


image.png

現(xiàn)在的商用虛擬機(jī)都采用這種算法來(lái)回收新生代,但1:1的比例非常不科學(xué)射众,因此新生代的內(nèi)存被劃分為一塊較大的Eden空間和兩塊較小的Survivor空間碟摆,每次使用Eden和其中一塊Survivor。每次回收時(shí)叨橱,將Eden和Survivor中還存活著的對(duì)象一次性復(fù)制到另外一塊Survivor空間上典蜕,最后清理掉Eden和剛才用過(guò)的Survivor空間。HotSpot虛擬機(jī)默認(rèn)Eden區(qū)和Survivor區(qū)的比例為8:1雏逾,每次新生代中可用內(nèi)存空間為整個(gè)新生代容量的90%嘉裤。當(dāng)Survivor空間不夠用時(shí),需要依賴(lài)?yán)夏甏M(jìn)行分配擔(dān)保(Handle Promotion)栖博。

3.標(biāo)記-整理(Mark-Compact)算法:

復(fù)制算法在對(duì)象存活率較高的場(chǎng)景下要進(jìn)行大量的復(fù)制操作屑宠,效率很低。萬(wàn)一對(duì)象100%存活仇让,那么需要有額外的空間進(jìn)行分配擔(dān)保典奉。老年代都是不易被回收的對(duì)象,對(duì)象存活率高丧叽,因此一般不能直接選用復(fù)制算法卫玖。根據(jù)老年代的特點(diǎn),有人提出了另外一種標(biāo)記-整理算法踊淳,過(guò)程與標(biāo)記-清除算法一樣假瞬,不過(guò)不是直接對(duì)可回收對(duì)象進(jìn)行清理,而是讓所有存活對(duì)象都向一端移動(dòng)迂尝,然后直接清理掉邊界以外的內(nèi)存脱茉。

標(biāo)志-整理算法執(zhí)行圖:


image.png

4.分代收集算法:

分代收集算法執(zhí)行圖:


image.png

小結(jié):

根據(jù)對(duì)象的生命周期的不同將內(nèi)存劃分為幾塊,然后根據(jù)各塊的特點(diǎn)采用最適當(dāng)?shù)氖占惴⒖4笈鷮?duì)象死去琴许、少量對(duì)象存活的(新生代),使用復(fù)制算法溉躲,復(fù)制成本低榜田;對(duì)象存活率高益兄、沒(méi)有額外空間進(jìn)行分配擔(dān)保的(老年代),采用標(biāo)記-清理算法或者標(biāo)記-整理算法箭券。

常見(jiàn)垃圾收集器:

1.Serial收集器:

最基本净捅、發(fā)展歷史最久的收集器,這個(gè)收集器是一個(gè)采用復(fù)制算法的單線程的收集器邦鲫,單線程一方面意味著它只會(huì)使用一個(gè)CPU或一條線程去完成垃圾收集工作灸叼,另一方面也意味著它進(jìn)行垃圾收集時(shí)必須暫停其他線程的所有工作神汹,直到它收集結(jié)束為止庆捺。后者意味著,在用戶(hù)不可見(jiàn)的情況下要把用戶(hù)正常工作的線程全部停掉屁魏,這對(duì)很多應(yīng)用是難以接受的滔以。

不過(guò)實(shí)際上到目前為止,Serial收集器依然是虛擬機(jī)運(yùn)行在Client模式下的默認(rèn)新生代收集器氓拼,因?yàn)樗?jiǎn)單而高效你画。用戶(hù)桌面應(yīng)用場(chǎng)景中,分配給虛擬機(jī)管理的內(nèi)存一般來(lái)說(shuō)不會(huì)很大桃漾,收集幾十兆甚至一兩百兆的新生代停頓時(shí)間在幾十毫秒最多一百毫秒坏匪,只要不是頻繁發(fā)生,這點(diǎn)停頓是完全可以接受的撬统。

Serial收集器運(yùn)行過(guò)程如下圖所示:


image.png

說(shuō)明:
1.需要STW(Stop The World)适滓,停頓時(shí)間長(zhǎng)。
2.簡(jiǎn)單高效恋追,對(duì)于單個(gè)CPU環(huán)境而言凭迹,Serial收集器由于沒(méi)有線程交互開(kāi)銷(xiāo),可以獲取最高的單線程收集效率苦囱。

2.ParNew收集器:

ParNew收集器其實(shí)就是Serial收集器的多線程版本嗅绸,除了使用多條線程進(jìn)行垃圾收集外,其余行為和Serial收集器完全一樣撕彤,包括使用的也是復(fù)制算法鱼鸠。ParNew收集器除了多線程以外和Serial收集器并沒(méi)有太多創(chuàng)新的地方,但是它卻是Server模式下的虛擬機(jī)首選的新生代收集器羹铅,其中有一個(gè)很重要的和性能無(wú)關(guān)的原因是蚀狰,除了Serial收集器外,目前只有它能與CMS收集器配合工作睦裳。

ParNew收集器在單CPU的環(huán)境中絕對(duì)不會(huì)有比Serial收集器更好的效果造锅,甚至由于線程交互的開(kāi)銷(xiāo),該收集器在兩個(gè)CPU的環(huán)境中都不能百分之百保證可以超越Serial收集器廉邑。隨著可用CPU數(shù)量的增加哥蔚,它對(duì)于GC時(shí)系統(tǒng)資源的有效利用還是很有好處的倒谷。它默認(rèn)開(kāi)啟的收集線程數(shù)與CPU數(shù)量相同,在CPU數(shù)量非常多的情況下糙箍,可以使用-XX:ParallelGCThreads參數(shù)來(lái)限制垃圾收集的線程數(shù)渤愁。

ParNew收集器運(yùn)行過(guò)程如下圖所示:


image.png

3.Parallel Scavenge收集器:

Parallel Scavenge收集器也是一個(gè)新生代收集器,也是用復(fù)制算法的收集器深夯,也是并行的多線程收集器抖格。CMS等收集器的關(guān)注點(diǎn)是盡可能縮短垃圾收集時(shí)用戶(hù)線程的停頓時(shí)間,而Parallel Scavenge收集器的目標(biāo)則是達(dá)到一個(gè)可控制的吞吐量咕晋。

吞吐量:CPU用于運(yùn)行用戶(hù)代碼時(shí)間與CPU總消耗時(shí)間的比值雹拄,即吞吐量=運(yùn)行用戶(hù)代碼時(shí)間/(運(yùn)行用戶(hù)代碼時(shí)間+垃圾收集時(shí)間),虛擬機(jī)總運(yùn)行100分鐘掌呜,垃圾收集1分鐘滓玖,那吞吐量就是99%。

Parallel Scavenge收集器是虛擬機(jī)運(yùn)行在Server模式下的默認(rèn)垃圾收集器质蕉。

4.Serial Old收集器:

Serial收集器的老年代版本势篡,同樣是一個(gè)單線程收集器,使用“標(biāo)記-整理算法”模暗,這個(gè)收集器的主要意義也是在于給Client模式下的虛擬機(jī)使用禁悠。

5.Parallel Old收集器:

Parallel Scavenge收集器的老年代版本,使用多線程和“標(biāo)記-整理”算法兑宇。在注重吞吐量以及CPU資源敏感的場(chǎng)合碍侦,都可以?xún)?yōu)先考慮Parallel Scavenge收集器+Parallel Old收集器的組合。

運(yùn)行過(guò)程如下圖所示:


image.png

6.CMS收集器:

CMS(Conrrurent Mark Sweep)收集器是以獲取最短回收停頓時(shí)間為目標(biāo)的收集器顾孽。使用標(biāo)記 - 清除算法祝钢,收集過(guò)程分為如下四步:

1.初始標(biāo)記,標(biāo)記GCRoots能直接關(guān)聯(lián)到的對(duì)象若厚,時(shí)間很短拦英。
2.并發(fā)標(biāo)記,進(jìn)行GCRoots Tracing(可達(dá)性分析)過(guò)程测秸,時(shí)間很長(zhǎng)疤估。
3.重新標(biāo)記,修正并發(fā)標(biāo)記期間因用戶(hù)程序繼續(xù)運(yùn)作而導(dǎo)致標(biāo)記產(chǎn)生變動(dòng)的那一部分對(duì)象的標(biāo)記記錄霎冯,時(shí)間較長(zhǎng)铃拇。
4.并發(fā)清除,回收內(nèi)存空間沈撞,時(shí)間很長(zhǎng)慷荔。
其中,并發(fā)標(biāo)記與并發(fā)清除兩個(gè)階段耗時(shí)最長(zhǎng)缠俺,但是可以與用戶(hù)線程并發(fā)執(zhí)行显晶。

運(yùn)行過(guò)程如下圖所示:


image.png

說(shuō)明:
1.對(duì)CPU資源非常敏感贷岸,可能會(huì)導(dǎo)致應(yīng)用程序變慢,吞吐率下降磷雇。

2.無(wú)法處理浮動(dòng)垃圾偿警,因?yàn)樵诓l(fā)清理階段用戶(hù)線程還在運(yùn)行,自然就會(huì)產(chǎn)生新的垃圾唯笙,而在此次收集中無(wú)法收集他們螟蒸,只能留到下次收集,這部分垃圾為浮動(dòng)垃圾崩掘,同時(shí)七嫌,由于用戶(hù)線程并發(fā)執(zhí)行,所以需要預(yù)留一部分老年代空間提供并發(fā)收集時(shí)程序運(yùn)行使用呢堰。

3.由于采用的標(biāo)記 - 清除算法抄瑟,會(huì)產(chǎn)生大量的內(nèi)存碎片凡泣,不利于大對(duì)象的分配枉疼,可能會(huì)提前觸發(fā)一次Full GC。虛擬機(jī)提供了-XX:+UseCMSCompactAtFullCollection參數(shù)來(lái)進(jìn)行碎片的合并整理過(guò)程鞋拟,這樣會(huì)使得停頓時(shí)間變長(zhǎng)骂维,虛擬機(jī)還提供了一個(gè)參數(shù)配置,-XX:+CMSFullGCsBeforeCompaction贺纲,用于設(shè)置執(zhí)行多少次不壓縮的Full GC后航闺,接著來(lái)一次帶壓縮的GC。

7.G1收集器:

與其他GC收集器相比猴誊,G1收集器有以下特點(diǎn):
1.并行和并發(fā)潦刃。使用多個(gè)CPU來(lái)縮短Stop The World停頓時(shí)間,與用戶(hù)線程并發(fā)執(zhí)行懈叹。
2.分代收集乖杠。獨(dú)立管理整個(gè)堆,但是能夠采用不同的方式去處理新創(chuàng)建對(duì)象和已經(jīng)存活了一段時(shí)間澄成、熬過(guò)多次GC的舊對(duì)象胧洒,以獲取更好的收集效果。
3.空間整合墨状∥缆基于標(biāo)記 - 整理算法,無(wú)內(nèi)存碎片產(chǎn)生肾砂。
4.可預(yù)測(cè)的停頓列赎。能簡(jiǎn)歷可預(yù)測(cè)的停頓時(shí)間模型,能讓使用者明確指定在一個(gè)長(zhǎng)度為M毫秒的時(shí)間片段內(nèi)镐确,消耗在垃圾收集上的時(shí)間不得超過(guò)N毫秒包吝。

在G1之前的垃圾收集器肛根,收集的范圍都是整個(gè)新生代或者老年代,而G1不再是這樣漏策。使用G1收集器時(shí)派哲,Java堆的內(nèi)存布局與其他收集器有很大差別,它將整個(gè)Java堆劃分為多個(gè)大小相等的獨(dú)立區(qū)域(Region)掺喻,雖然還保留有新生代和老年代的概念感耙,但新生代和老年代不再是物理隔離的了,它們都是一部分(可以不連續(xù))Region的集合。

理解GC日志:

[GC [DefNew: 310K->194K(2368K), 0.0269163 secs] 310K->194K(7680K), 0.0269513 secs] [Times: user=0.00 sys=0.00, real=0.03 secs] 
[GC [DefNew: 2242K->0K(2368K), 0.0018814 secs] 2242K->2241K(7680K), 0.0019172 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
[Full GC (System) [Tenured: 2241K->193K(5312K), 0.0056517 secs] 4289K->193K(7680K), [Perm : 2950K->2950K(21248K)], 0.0057094 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
Heap
def new generation   total 2432K, used 43K [0x00000000052a0000, 0x0000000005540000, 0x0000000006ea0000)
eden space 2176K,   2% used [0x00000000052a0000, 0x00000000052aaeb8, 0x00000000054c0000)
from space 256K,   0% used [0x00000000054c0000, 0x00000000054c0000, 0x0000000005500000)
to   space 256K,   0% used [0x0000000005500000, 0x0000000005500000, 0x0000000005540000)
tenured generation   total 5312K, used 193K [0x0000000006ea0000, 0x00000000073d0000, 0x000000000a6a0000)
the space 5312K,   3% used [0x0000000006ea0000, 0x0000000006ed0730, 0x0000000006ed0800, 0x00000000073d0000)
compacting perm gen  total 21248K, used 2982K [0x000000000a6a0000, 0x000000000bb60000, 0x000000000faa0000)
the space 21248K,  14% used [0x000000000a6a0000, 0x000000000a989980, 0x000000000a989a00, 0x000000000bb60000)
No shared spaces configured.

說(shuō)明:

1.日志的開(kāi)頭“GC”僻澎、“Full GC”表示這次垃圾收集的停頓類(lèi)型,而不是用來(lái)區(qū)分新生代GC還是老年代GC的砸捏。如果有Full,則說(shuō)明本次GC停止了其他所有工作線程(Stop-The-World)∶昂冢看到Full GC的寫(xiě)法是“Full GC(System)”芒划,這說(shuō)明是調(diào)用System.gc()方法所觸發(fā)的GC拼苍。

2.“GC”中接下來(lái)的“[DefNew”表示GC發(fā)生的區(qū)域,這里顯示的區(qū)域名稱(chēng)與使用的GC收集器是密切相關(guān)的早处,例如上面樣例所使用的Serial收集器中的新生代名為“Default New Generation”,所以顯示的是“[DefNew”。如果是ParNew收集器,新生代名稱(chēng)就會(huì)變?yōu)椤癧ParNew”嚷往,意為“Parallel New Generation”。如果采用Parallel Scavenge收集器柠衅,那它配套的新生代稱(chēng)為“PSYoungGen”皮仁,老年代和永久代同理,名稱(chēng)也是由收集器決定的。

3.后面方括號(hào)內(nèi)部的“310K->194K(2368K)”贷祈,指的是該區(qū)域已使用的容量->GC后該內(nèi)存區(qū)域已使用的容量(該內(nèi)存區(qū)總?cè)萘?趋急。方括號(hào)外面的“310K->194K(7680K)”,則指的是GC前Java堆已使用的容量->GC后Java堆已使用的容量(Java堆總?cè)萘?势誊。

4.再往后“0.0269163 secs”表示該內(nèi)存區(qū)域GC所占用的時(shí)間呜达,單位是秒。最后的“[Times: user=0.00 sys=0.00 real=0.03 secs]”則更具體了粟耻,user表示用戶(hù)態(tài)消耗的CPU時(shí)間闻丑、內(nèi)核態(tài)消耗的CPU時(shí)間、操作從開(kāi)始到結(jié)束經(jīng)過(guò)的墻鐘時(shí)間勋颖。后面兩個(gè)的區(qū)別是嗦嗡,墻鐘時(shí)間包括各種非運(yùn)算的等待消耗,比如等待磁盤(pán)I/O饭玲、等待線程阻塞侥祭,而CPU時(shí)間不包括這些耗時(shí),但當(dāng)系統(tǒng)有多CPU或者多核的話茄厘,多線程操作會(huì)疊加這些CPU時(shí)間矾湃,所以如果看到user或sys時(shí)間超過(guò)real時(shí)間是完全正常的。

5.“Heap”后面就列舉出堆內(nèi)存目前各個(gè)年代的區(qū)域的內(nèi)存情況户秤。


上一篇:Java基礎(chǔ)(4)—異常與內(nèi)部類(lèi)
下一篇:Java基礎(chǔ)(6)—Java虛擬機(jī) JVM

精彩內(nèi)容不夠看睬关?更多精彩內(nèi)容,請(qǐng)到微信搜索 “危君子頻道” 訂閱號(hào)窑滞,每天更新琼牧,歡迎大家關(guān)注訂閱!

image

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末哀卫,一起剝皮案震驚了整個(gè)濱河市巨坊,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌此改,老刑警劉巖趾撵,帶你破解...
    沈念sama閱讀 218,036評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異共啃,居然都是意外死亡占调,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,046評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門(mén)移剪,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)究珊,“玉大人,你說(shuō)我怎么就攤上這事挂滓】嘁” “怎么了啸胧?”我有些...
    開(kāi)封第一講書(shū)人閱讀 164,411評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)幔虏。 經(jīng)常有香客問(wèn)我纺念,道長(zhǎng),這世上最難降的妖魔是什么想括? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,622評(píng)論 1 293
  • 正文 為了忘掉前任陷谱,我火速辦了婚禮,結(jié)果婚禮上瑟蜈,老公的妹妹穿的比我還像新娘烟逊。我一直安慰自己,他們只是感情好铺根,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,661評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布宪躯。 她就那樣靜靜地躺著,像睡著了一般位迂。 火紅的嫁衣襯著肌膚如雪访雪。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 51,521評(píng)論 1 304
  • 那天掂林,我揣著相機(jī)與錄音臣缀,去河邊找鬼。 笑死泻帮,一個(gè)胖子當(dāng)著我的面吹牛精置,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播锣杂,決...
    沈念sama閱讀 40,288評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼脂倦,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了蹲堂?” 一聲冷哼從身側(cè)響起狼讨,我...
    開(kāi)封第一講書(shū)人閱讀 39,200評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎柒竞,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體播聪,經(jīng)...
    沈念sama閱讀 45,644評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡朽基,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,837評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了离陶。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片稼虎。...
    茶點(diǎn)故事閱讀 39,953評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖招刨,靈堂內(nèi)的尸體忽然破棺而出霎俩,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 35,673評(píng)論 5 346
  • 正文 年R本政府宣布打却,位于F島的核電站杉适,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏柳击。R本人自食惡果不足惜猿推,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,281評(píng)論 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望捌肴。 院中可真熱鬧蹬叭,春花似錦、人聲如沸状知。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,889評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)饥悴。三九已至坦喘,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間铺坞,已是汗流浹背起宽。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,011評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留济榨,地道東北人坯沪。 一個(gè)月前我還...
    沈念sama閱讀 48,119評(píng)論 3 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像擒滑,于是被迫代替她去往敵國(guó)和親腐晾。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,901評(píng)論 2 355