当前位置:编程学习 > JAVA >>

GC悲观策略之Parallel GC篇

先来看段代码:
Java代码 
import java.util.*;  
public class SummaryCase{ 
    public static void main(String[] args) throws Exception{     
        List<Object> caches=new ArrayList<Object>();     
        for(int i=0;i<7;i++){     
            caches.add(new byte[1024*1024*3]);     
        }     
        caches.clear();     
        for(int i=0;i<2;i++){        
        caches.add(new byte[1024*1024*3]);     
        }     
        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 。
这里的原因就在于Parallel Scavenge GC时的悲观策略,当在eden上分配内存失败时且对象的大小尚不需要直接在old上分配时,会触发YGC,代码片段如下:
Cpp代码 
void PSScavenge::invoke(){ 
    ...  
    bool scavenge_was_done = PSScavenge::invoke_no_policy(); 
    PSGCAdaptivePolicyCounters* counters = heap->gc_policy_counters(); 
    if (UsePerfData) 
        counters->update_full_follows_scavenge(0); 
    if(!scavenge_was_done || policy->should_full_GC(heap->old_gen()->free_in_bytes())){ 
        if(UsePerfData) 
            counters->update_full_follows_scavenge(full_follows_scavenge); 
            < GCCauseSetter gccs(heap, GCCause::_adaptive_size_policy);  
        if (UseParallelOldGC){ 
            PSParallelCompact::invoke_no_policy(false); 
        }else{ 
            PSMarkSweep::invoke_no_policy(false);  
        } 
    } 
    ... 

PSScavenge::invoke_no_policy{ 
    ...  
    if(!should_attempt_scavenge()){ 
        return false; 
    } 
    ... 

bool PSScavenge::should_attempt_scavenge(){ 
    ... 
    PSAdaptiveSizePolicy* policy = heap->size_policy(); 
    size_t avg_promoted = (size_t) policy->padded_average_promoted_in_bytes(); 
    size_t promotion_estimate = MIN2(avg_promoted, young_gen->used_in_bytes()); 
    bool result = promotion_estimate < old_gen->free_in_bytes(); 
    ... 
    return result; 

在上面should_attempt_scavenge代码片段中,可以看到会比较之前YGC晋升到Old中的平均大小与当前新生代中已被使用的字节数大小,取更小的值与旧生代目前剩余空间大小对比,如更大,则返回false,就终止了YGC的执行了,当返回false时,PSScavenge::invoke就将触发Full GC了。
在PSScavenge:invoke中还有一个条件为:policy->should_full_GC(heap->old_gen()->free_in_bytes(),来看看这段代码片段:
Cpp代码 
bool PSAdaptiveSizePolicy::should_full_GC(size_t old_free_in_bytes){ 
    bool result = padded_average_promoted_in_bytes() > (float) old_free_in_bytes; 
    ... 
    return result; 

可看到,这段代码检查的也是之前YGC时晋升到old的平均大小是否大于了旧生代的剩余空间,如大于,则触发full gc。
总结上面分析的策略,可以看到采用Parallel GC的情况下,当YGC触发时,会有两个检查:
1、在YGC执行前,min(目前新生代已使用的大小,之前平均晋升到old的大小中的较小值) > 旧生代剩余空间大小 ? 不执行YGC,直接执行Full GC : 执行YGC;
2、在YGC执行后,平均晋升到old的大小 > 旧生代剩余空间大小 ? 触发Full GC : 什么都不做。
 
按照这样的说明,再来看看上面代码的执行过程中eden和old大小的变化状况:

 

代码

Eden

Old

YGC

FGC

第一次循环

3

0

0

0

第二次循环

6

0

0

0

第三次循环

3

6

1

0

第四次循环

6

6

1

0

第五次循环

3

12

2

0

第六次循环

6

12

2

0

第七次循环

3

18

3

1

第八次循环

6

18

3

1

第九次循环

补充:软件开发 , Java ,
CopyRight © 2012 站长网 编程知识问答 www.zzzyk.com All Rights Reserved
部份技术文章来自网络,