轉載 JAVA gc垃圾回收機制

thanks:https://m.oschina.net/u/123553算法

 

 

1、GC概要
 
JVM堆相關知識
    爲何先說JVM堆?
    JVM的堆是Java對象的活動空間,程序中的類的對象從中分配空間,其存儲着正在運行着的應用程序用到的全部對象。這些對象的創建方式就是那些new一類的操做,當對象無用後,是GC來負責這個無用的對象(地球人都知道)。
JVM堆
    (1) 新域:存儲全部新成生的對象
    (2) 舊域:新域中的對象,通過了必定次數的GC循環後,被移入舊域
    (3)永久域:存儲類和方法對象,從配置的角度看,這個域是獨立的,不包括在JVM堆內。默認爲4M。
 
新域會被分爲3個部分:1.第一個部分叫Eden。(伊甸園??多是由於亞當和夏娃是人類最先的活動對象?)2.另兩個部分稱爲輔助生存空間(幼兒園),我這裏一個稱爲A空間(From sqace),一個稱爲B空間(To Space)。.net


2、GC淺談
GC的工做目的很明確:在堆中,找到已經無用的對象,並把這些對象佔用的空間收回使其能夠從新利用.大多數垃圾回收的 算法思路都是一致的:把全部對象組成一個集合,或能夠理解爲樹狀結構,從樹根開始找,只要能夠找到的都是活動對象,若是找不到,這個對象就是凋零的昨日黃 花,應該被回收了。
在sun 的文檔說明中,對JVM堆的新域,是採用coping算法,該算法的提出是爲了克服句柄的開銷和解決堆碎片的垃圾回收。它開始時把堆分紅一個對象面和多個 空閒面,程序從對象面爲對象分配空間,當對象滿了,基於 coping算法的垃圾收集就從根集中掃描活動對象,並將每一個活動對象複製到空閒面(使得活動對象所佔的內存之間沒有空閒洞),這樣空閒面變成了對象面, 原來的對象面變成了空閒面,程序會在新的對象面中分配內存。
 
對於新生成的對象,都放在Eden中;當Eden充滿時(小孩太多 了),GC將開始工做,首先中止應用程序的運行,開始收集垃圾,把全部可找到的對象都複製到A空間中,一旦當A空間充滿,GC就把在A空間中可找到的對象 都複製到B空間中(會覆蓋原有的存儲對象),當B空間滿的時間,GC就把在B空間中可找到的對象都複製到A空間中,AB在這個過程當中互換角色,那位客官說 了:拷來拷去,煩不煩啊?何時是頭?您別急,在活動對象通過必定次數的GC操做後,這些活動對象就會被放到舊域中。對於這些活動對象,新域的幼兒園生 活結束了。新域爲何要這麼折騰?起初在這塊我也很迷糊,又查了些資料,原來是這樣:應用程序生成的絕大部分對象都是短命的,copying算法最理想的 狀態是,全部移出Eden的對象都會被收集,由於這些都是短命鬼,通過必定次數的GC後應該被收集,那麼移入到舊域的對象都是長命的,這樣能夠防止AB空 間的來回複製影響應用程序。實際上這種理想狀態是很難達到的,應用程序中不可避免地存在長命的對象,copying算法的發明者要這些對象都儘可能放在新域 中,以保證小範圍的複製,壓縮舊域的開銷可比新域中的複製大得多(舊域在下面說)。對於舊域,採用的是tracing算法的一種,稱爲標記-清除-壓縮收 集器,注意,這有一個壓縮,這是個開銷挺大的操做。垃圾回收主要是對Young Generation塊和Old Generation塊內存進行回收,YG用來放新產生的對象,通過幾回回收還沒回收掉的對象往OG中移動,對YG進行垃圾回收又叫作MinorGC,對 OG垃圾回收又叫MajorGC,兩塊內存回收互不干涉。2、Gc 流程:
[older generation][survivor 1][survivor 2][eden]
*young generation=eden + survivor
1.當eden滿了,觸發young GC;
2.young GC作2件事:一,去掉一部分沒用的object;二,把老的還被引用的object發到survior裏面,等下幾回GC之後,survivor再放到old裏面。
3.當old滿了,觸發full GC。full GC很消耗內存,把old,young裏面大部分垃圾回收掉。這個時候用戶線程都會被block。
 
3、young generation比例越大,不必定最好。
將young的大小設置爲大於總堆大小的一半時會形成效率低下。若是設置得太小,又會由於young generation收集程序不得不頻繁運行而形成瓶頸。
 
4、總結
從上面的推導能夠得出不少結論,下面是前輩的經驗總結與自已的認識
1.JVM堆的大小決定了GC的運行時間。若是JVM堆的大小超過必定的限度,那麼GC的運行時間會很長。
2.對象生存的時間越長,GC須要的回收時間也越長,影響了回收速度。
3.大多數對象都是短命的,因此,若是能讓這些對象的生存期在GC的一次運行週期內,wonderful!
4.應用程序中,創建與釋放對象的速度決定了垃圾收集的頻率。
5.若是GC一次運行週期超過3-5秒,這會很影響應用程序的運行,若是能夠,應該減小JVM堆的大小了。
6.前輩經驗之談:一般狀況下,JVM堆的大小應爲物理內存的80%。
 
5、看案例
jmap -heap 2343
Attaching to process ID 2343, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 11.0-b16
 
using thread-local object allocation.
Parallel GC with 8 thread(s)
 
Heap Configuration:
   MinHeapFreeRatio = 40
   MaxHeapFreeRatio = 70
   MaxHeapSize      = 4294967296 (4096.0MB)
   NewSize          = 2686976 (2.5625MB)
   MaxNewSize       = -65536 (-0.0625MB)
   OldSize          = 5439488 (5.1875MB)
   NewRatio         = 2                  (YG,OG 大小比爲1:2)
   SurvivorRatio    = 8
   PermSize         = 21757952 (20.75MB)
   MaxPermSize      = 268435456 (256.0MB)
 
Heap Usage:
PS Young Generation
Eden Space:
   capacity = 1260060672 (1201.6875MB)
   used     = 64868288 (61.86322021484375MB)
   free     = 1195192384 (1139.8242797851562MB)
   5.148028935546367% used
From Space:
   capacity = 85524480 (81.5625MB)
   used     = 59457648 (56.70323181152344MB)
   free     = 26066832 (24.859268188476562MB)
   69.52120375359195% used
To Space:
   capacity = 85852160 (81.875MB)
   used     = 0 (0.0MB)
   free     = 85852160 (81.875MB)
   0.0% used
~~~~~~~~~~~~~~~~~~~~~~~~~~這三塊爲上面所說的YG大小和使用狀況
PS Old Generation
   capacity = 2291138560 (2185.0MB)
   used     = 1747845928 (1666.8757705688477MB)
   free     = 543292632 (518.1242294311523MB)
   76.28722062099989% used
~~~~~~~~~~~~~~~~~~~~~~~~~~OG大小和使用狀況
PS Perm Generation
   capacity = 108265472 (103.25MB)
   used     = 107650712 (102.6637191772461MB)
   free     = 614760 (0.5862808227539062MB)
   99.43217353728436% used
 
這臺機器簡單說YG內存1G,OG內存2G,總內存4G
在這樣的配置下,GC運行狀況:
jstat -gcutil -h5 2343 4s 100
  S0     S1     E      O      P     YGC     YGCT    FGC    FGCT     GCT  
 79.82   0.00  75.34  78.55  99.44   7646 1221.668   398 2052.993 3274.661
  0.00  79.52   0.62  78.63  99.44   7647 1221.782   398 2052.993 3274.775 這裏發生了一次YG GC,也就是MinorGC,耗時0.12s
  0.00  79.52  28.95  78.63  99.44   7647 1221.782   398 2052.993 3274.775
  0.00  79.52  46.34  78.63  99.44   7647 1221.782   398 2052.993 3274.775
 
同時能夠看到總共進行了398次Major GC 總耗時2052.993 因此每次Major GC時間爲:2052.993/398=5.16秒
這是個很嚴重的問題,進行Major GC的時候程序會暫停,沒法響應,竟然會暫停5秒多,這誰都沒法接受吧 :)
一樣Minor GC進行了7647次,總用時1221.782 平均時間爲0.16秒,算是能夠接受
 線程

再來看看修改配置後:
jmap -heap 14103
Attaching to process ID 14103, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 11.0-b16
 
using parallel threads in the new generation.
using thread-local object allocation.
Concurrent Mark-Sweep GC
 
Heap Configuration:
   MinHeapFreeRatio = 40
   MaxHeapFreeRatio = 70
   MaxHeapSize      = 4294967296 (4096.0MB)
   NewSize          = 536870912 (512.0MB)
   MaxNewSize       = 536870912 (512.0MB)
   OldSize          = 5439488 (5.1875MB)
   NewRatio         =4                         YG:OG          1:4       
   SurvivorRatio    = 8
   PermSize         = 268435456 (256.0MB)
   MaxPermSize      = 268435456 (256.0MB)
 
Heap Usage:
New Generation (Eden + 1 Survivor Space):
   capacity = 483196928 (460.8125MB)
   used     = 428284392 (408.4438247680664MB)
   free     = 54912536 (52.368675231933594MB)
   88.63557841162434% used
Eden Space:
   capacity = 429522944 (409.625MB)
   used     = 404788608 (386.0364990234375MB)
   free     = 24734336 (23.5885009765625MB)
   94.24144010337199% used
From Space:
   capacity = 53673984 (51.1875MB)
   used     = 23495784 (22.407325744628906MB)
   free     = 30178200 (28.780174255371094MB)
   43.77499534970238% used
To Space:
   capacity = 53673984 (51.1875MB)
   used     = 0 (0.0MB)
   free     = 53673984 (51.1875MB)
   0.0% used
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~YG 大小和使用狀態
concurrent mark-sweep generation:
   capacity = 3758096384 (3584.0MB)
   used     = 1680041600 (1602.2125244140625MB)
   free     = 2078054784 (1981.7874755859375MB)
   44.70459052494594% used
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~OG 大小和使用狀態
Perm Generation:
   capacity = 268435456 (256.0MB)
   used     = 128012184 (122.0819320678711MB)
   free     = 140423272 (133.9180679321289MB)
   47.688254714012146% used
 
在這個配置下,GC運行狀況:
jstat -gcutil -h5 14103 4s 100
  S0     S1     E      O      P     YGC     YGCT    FGC    FGCT     GCT  
 47.49   0.00  64.82  46.08  47.69  20822 2058.631    68   22.734 2081.365
  0.00  37.91  38.57  46.13  47.69  20823 2058.691    68   22.734 2081.425 這裏發生了一次YG GC,也就是MinorGC,耗時0.06s
 46.69   0.00  15.19  46.18  47.69  20824 2058.776    68   22.734 2081.510
 46.69   0.00  74.59  46.18  47.69  20824 2058.776    68   22.734 2081.510
  0.00  40.29  19.95  46.24  47.69  20825 2058.848    68   22.734 2081.582
 
MajorGC平均時間:22.734/68=0.334秒(上面是5秒多吧)
MinorGC平均時間:2058.691/20823=0.099秒(比上面略少)對象

相關文章
相關標籤/搜索