GC悲觀策略之Parallel GC

2022-09-11 13:06:10 字數 3514 閱讀 7494

先來看段**:

import

j**a.util.arraylist;

import

j**a.util.list;

/*** -xms30m -xmx30m -xmn10m -xx:+useparallelgc

* @author

liuxiao**/

public

class

test1

caches.clear();

for(int i=0;i<2;i++)

thread.sleep(10000);

}}

當用-xms30m -xmx30m -xmn10m -xx:+useparallelgc 執行上面的**時會執行幾次minor gc和幾次full gc呢?

按照eden空間不足時觸發minor gc的規則,上面**執行後的gc應為:m、m、m、m ,但實際上上面**執行後gc則為:m、m、m、f、f 。具體gc日誌如下:

[gc [psyounggen: 7470k->852k(9216k)] 7470k->6996k(29696k), 0.0765494 secs] [times: user=0.03 sys=0.02, real=0.08secs] 

[gc [psyounggen: 7091k->772k(9216k)] 13235k->13060k(29696k), 0.0320251 secs] [times: user=0.05 sys=0.00, real=0.03secs]

[gc [psyounggen: 7062k->756k(9216k)] 19350k->19196k(29696k), 0.0111223 secs] [times: user=0.03 sys=0.03, real=0.01secs]

[full gc [psyounggen: 756k->0k(9216k)] [paroldgen: 18440k->19142k(20480k)] 19196k->19142k(29696k) [pspermgen: 2665k->2664k(21504k)], 0.0318487 secs] [times: user=0.08 sys=0.00, real=0.03secs]

[full gc [psyounggen: 6185k->0k(9216k)] [paroldgen: 19142k->3782k(20480k)] 25327k->3782k(29696k) [pspermgen: 2664k->2664k(21504k)], 0.0168417 secs] [times: user=0.01 sys=0.00, real=0.02secs]

heap

psyounggen total 9216k, used 3263k [0x00000000ff600000, 0x0000000100000000, 0x0000000100000000)

eden space 8192k, 39% used [0x00000000ff600000,0x00000000ff92fc28,0x00000000ffe00000)

from space 1024k, 0% used [0x00000000ffe00000,0x00000000ffe00000,0x00000000fff00000)

to space 1024k, 0% used [0x00000000fff00000,0x00000000fff00000,0x0000000100000000)

paroldgen total 20480k, used 3782k [0x00000000fe200000, 0x00000000ff600000, 0x00000000ff600000)

object space 20480k, 18% used [0x00000000fe200000,0x00000000fe5b1aa0,0x00000000ff600000)

pspermgen total 21504k, used 2671k [0x00000000f9000000, 0x00000000fa500000, 0x00000000fe200000)

object space 21504k, 12% used [0x00000000f9000000,0x00000000f929bc00,0x00000000fa500000)

分析:heap大小30m,根據預設的1:2原則,young大小10m、turned大小20m;

再根據8:1:1原則,eden大小8m,from大小1m,to大小1m。

為什麼第四次發生了full gc?這裡的原因就在於parallel sc**enge gc時的悲觀策略,當在eden上分配記憶體失敗時且物件的大小尚不需要直接在old上分配時,會觸發ygc,**片段如下:

void

pssc**enge::invoke()

else

}  

...

} pssc**enge::invoke_no_policy

...

} bool pssc**enge::should_attempt_sc**enge()

在上面should_attempt_sc**enge**片段中,可以看到會比較之前ygc晉公升到old中的平均大小與當前新生代中已被使用的位元組數大小,取更小的值與舊生代目前剩餘空間大小對比,如更大,則返回false,就終止了ygc的執行了,當返回false時,pssc**enge::invoke就將觸發full gc了。

在pssc**enge:invoke中還有乙個條件為:policy->should_full_gc(heap->old_gen()->free_in_bytes(),來看看這段**片段:

bool psadaptivesizepolicy::should_full_gc(size_t old_free_in_bytes)

可看到,這段**檢查的也是之前ygc時晉公升到old的平均大小是否大於了舊生代的剩餘空間,如大於,則觸發full gc。

總結上面分析的策略,可以看到採用parallel gc的情況下,當ygc觸發時,會有兩個檢查:

1、在ygc執行前,min(目前新生代已使用的大小,之前平均晉公升到old的大小中的較小值) > 舊生代剩餘空間大小 ? 不執行ygc,直接執行full gc : 執行ygc;

2、在ygc執行後,平均晉公升到old的大小 > 舊生代剩餘空間大小 ? 觸發full gc : 什麼都不做。

按照這樣的說明,再來看看上面**的執行過程中eden和old大小的變化狀況:

在第7次迴圈時,ygc後舊生代剩餘空間為2m,而之前平均晉級到old的物件大小為6m,因此在ygc後會觸發一次fgc。

而第9次迴圈時,在ygc執行前,此時新生代已使用的大小為6m,之前晉級到old的平均大小為6m,這兩者去最小值為6m,這個值已大於old的剩餘空間,因此就不執行ygc,直接執行fgc了。

sun jdk之所以要有悲觀策略,我猜想理由是程式最終是會以乙個較為穩態的狀況執行的,此時每次ygc後晉公升到old的物件大小應該是差不多的,在ygc時做好檢查,避免等ygc後晉公升到old的物件導致old空間不足,因此還不如乾脆就直接執行fgc,正因為悲觀策略的存在,大家有些時候可能會看到old空間沒滿但full gc執行的狀況。

**

C 多執行緒七之Parallel

1 簡介 關於parallel不想說太多,因為它是task的語法糖,至少我是這麼理解的,官方文件也是這麼說的,它本身就是基本task的.假設我們有乙個集合,不管是什麼集合,我們要遍歷它,首先想到的是for 如何涉及到修改或者讀可以用for 或者foreach 如果單純的讀 但是它兩是同步的去操作集合...

GC之CMS GC日誌分析

最近在學習jvm和gc調優,今天總結下cms的一些特點和要點,首先貼上乙個實際的cms gc log,先來解讀下各個元素。從下面的gc日誌可以看出,當前最新版本 jdk1.8 中的cms大致分為6步 1.cms initial mark 初始標記 2.cms concurrent mark 併發標記...

JVM系列二 GC策略 記憶體申請 物件衰老

jvm裡的gc garbage collection 的演算法有很多種,如標記清除收集器,壓縮收集器,分代收集器等等,詳見hotspot vm gc 的種類 現在比較常用的是分代收集 generational collection,也是sun vm使用的,j2se1.2之後引入 即將記憶體分為幾個區...