JVM學習小結(二)

GC收集日誌信息規律:[名稱:GC前內存佔用 -> GC後內存佔用 (該內存總大小)]

分代收集算法 次數上頻繁收集Young區

                       次數上較少收集Old區

                       基本不動元空間 

JVM在進行GC時,並非每次都對上面三個內存區域一起回收的,大部分時候回收的都是指新生代。
因此GC按照回收的區域又分了兩種類型,一種是普通GC(minor GC),一種是全局GC(major GC or Full GC)
 
Minor GC和Full GC的區別
  普通GC(minor GC):只針對新生代區域的GC,指發生在新生代的垃圾收集動作,因爲大多數Java對象存活率都不高,所以Minor GC非常頻繁,一般回收速度也比較快。 
  全局GC(major GC or Full GC):指發生在老年代的垃圾收集動作,出現了Major GC,經常會伴隨至少一次的Minor GC(但並不是絕對的)。Major GC的速度一般要比Minor GC慢上10倍以上

垃圾回收算法

1、引用計數法(瞭解) 

      缺點:每次對對象賦值時均要維護引用計數器,且計數器本身也有一定的消耗;

               較難處理循環引用(JVM的實現一般不採用這種方式)

2、複製算法

      年輕代的垃圾回收算法使用的是複製算法,複製算法的基本思想就是將內存分爲兩塊,每次只用其中一塊,當這一塊內存用完,就將還活着的對象複製到另外一塊上面。複製算法不會產生內存碎片。

  在GC開始的時候,對象只會存在於Eden區和名爲“From”的Survivor區,Survivor區“To”是空的。緊接着進行GC,Eden區中所有存活的對象都會被複制到“To”,而在“From”區中,仍存活的對象會根據他們的年齡值來決定去向。年齡達到一定值(年齡閾值,可以通過-XX:MaxTenuringThreshold來設置)的對象會被移動到年老代中,沒有達到閾值的對象會被複制到“To”區域。經過這次GC後,Eden區和From區已經被清空。這個時候,“From”和“To”會交換他們的角色,也就是新的“To”就是上次GC前的“From”,新的“From”就是上次GC前的“To”。不管怎樣,都會保證名爲To的Survivor區域是空的。Minor GC會一直重複這樣的過程,直到“To”區被填滿,“To”區被填滿之後,會將所有對象移動到年老代中。

  因爲Eden區對象一般存活率較低,一般的,使用兩塊10%的內存作爲空閒和活動區間,而另外80%的內存,則是用來給新建對象分配內存的。一旦發生GC,將10%的from活動區間與另外80%中存活的eden對象轉移到10%的to空閒區間,接下來,將之前90%的內存全部釋放,以此類推。

  複製算法它的缺點也是相當明顯的。 
  1、它浪費了一半的內存,這太要命了。 
  2、如果對象的存活率很高,我們可以極端一點,假設是100%存活,那麼我們需要將所有對象都複製一遍,並將所有引用地址重置一遍。複製這一工作所花費的時間,在對象存活率達到一定程度時,將會變的不可忽視。 所以從以上描述不難看出,複製算法要想使用,最起碼對象的存活率要非常低纔行,而且最重要的是,我們必須要克服50%內存的浪費。

3、標記清除算法(老年代)

      優點:不需要額外空間

      缺點:兩次掃描,耗時嚴重;

                 會產生內存碎片 

 4、標記壓縮(整理)算法(老年代)

       優點:標記的存活對象將會被整理,按照內存地址依次排列,而未被標記的內存會被清理掉。如此一來,當我們需要給新對象分配內存時,JVM只需要持有一個內存的起始地址即可,這比維護一個空閒列表顯然少了許多開銷。標記/整理算法不僅可以彌補標記/清除算法當中,內存區域分散的缺點,也消除了複製算法當中,內存減半的高額代價

       缺點:標記/整理算法唯一的缺點就是效率也不高,不僅要標記所有存活對象,還要整理所有存活對象的引用地址。
從效率上來說,標記/整理算法要低於複製算法

總結:

內存效率:複製算法>標記清除算法>標記整理算法(此處的效率只是簡單的對比時間複雜度,實際情況不一定如此)。 
內存整齊度:複製算法=標記整理算法>標記清除算法。 
內存利用率:標記整理算法=標記清除算法>複製算法。 
 
可以看出,效率上來說,複製算法是當之無愧的老大,但是卻浪費了太多內存,而爲了儘量兼顧上面所提到的三個指標,標記/整理算法相對來說更平滑一些,但效率上依然不盡如人意,它比複製算法多了一個標記的階段,又比標記/清除多了一個整理內存的過程

JMM: 俗稱java內存模型

          特徵:可見性、原子性、有序性

          CPU>內存>硬盤 

JMM(Java內存模型Java Memory Model,簡稱JMM)本身是一種抽象的概念 並不真實存在,它描述的是一組規則或規範通過規範定製了程序中各個變量(包括實例字段,靜態字段和構成數組對象的元素)的訪問方式.
JMM關於同步規定:
1.線程解鎖前,必須把共享變量的值刷新回主內存
2.線程加鎖前,必須讀取主內存的最新值到自己的工作內存
3.加鎖解鎖是同一把鎖
 
由於JVM運行程序的實體是線程,而每個線程創建時JVM都會爲其創建一個工作內存(有些地方成爲棧空間),工作內存是每個線程的私有數據區域,而Java內存模型中規定所有變量都存儲在主內存,主內存是共享內存區域,所有線程都可訪問,但線程對變量的操作(讀取賦值等)必須在工作內存中進行,首先要將變量從主內存拷貝到自己的工作空間,然後對變量進行操作,操作完成再將變量寫回主內存,不能直接操作主內存中的變量,各個線程中的工作內存儲存着主內存中的變量副本拷貝,因此不同的線程無法訪問對方的工作內存,此案成間的通訊(傳值) 必須通過主內存來完成

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章