CLR GC分析

CLR 的GC分为两个部分,一个是GC的内存分配,另外一个是GC的垃圾回收。这里我们先讲一下垃圾回收。(QQ群:676817308技术讨论群。欢迎您的加入)

一.垃圾回收的触发条件
1.在C#代码中调用 GC.Collection();
2.物理内存不足的情况下
3.分配量超过分配阈值
4.找不到可分配的内存空间
在满足了以上四个条件中的任何一个,CLR都会触发GC的垃圾回收,清理托管堆空间释放内存,以便下次使用。

二.垃圾回收的流程
1停止其它线程到并且切换到抢占模式(抢占模式不可访问托管堆代码,只可访问非托管)
2.重新定位回收的目标代,并且判断是否执行后台GC回收
3-1.如果执行后台GC回收分为两步(第一:后台标记(标记没被使用的托管堆空间),第二:后台清扫(清扫没被使用的托管堆空间))
3-2.如果不执行后台GC,则执行普通GC,普通GC一共分为五个阶段(1,标记。2计划。3.重定位。4.压缩。5清扫。)
4.恢复其它线程到合作模式
以上为GC垃圾回收的全部过程。

三.具体的实施细则
前面提到了垃圾回收的触发条件,第一个条件是直接在C#代码中调用GC.Collection.这个不用多说,人人都会。第二个是物理内存不足,获取物理内存信息调用了vc++标准函数GetProcessMemoryLoad,当获取的信息超过一定值的时候会触发GC回收。代码如下:

void GCToOSInterface::GetMemoryStatus(uint32_t* memory_load, uint64_t* available_physical, uint64_t* available_page_file)
{
   
    uint64_t restricted_limit = GetRestrictedPhysicalMemoryLimit();
    if (restricted_limit != 0)
    {
   
        size_t workingSetSize;
        BOOL status = FALSE;
        if (!g_UseRestrictedVirtualMemory)
        {
   
            PROCESS_MEMORY_COUNTERS pmc;
            status = GCGetProcessMemoryInfo(GetCurrentProcess(), &pmc, sizeof(pmc));
            workingSetSize = pmc.WorkingSetSize;
        }

        if(status)
        {
   
            if (memory_load)
                *memory_load = (uint32_t)((float)workingSetSize * 100.0 / (float)restricted_limit);
            if (available_physical)
            {
   
                if(workingSetSize > restricted_limit)
                    *available_physical = 0;
                else
                    *available_physical = restricted_limit - workingSetSize;
            }
            // Available page file doesn't mean much when physical memory is restricted since
            // we don't know how much of it is available to this process so we are not going to 
            // bother to make another OS call for it.
            if (available_page_file)
                *available_page_file = 0;

            return;
        }
    }

    MEMORYSTATUSEX ms;
    ::GetProcessMemoryLoad(&ms);
    
    if (g_UseRestrictedVirtualMemory)
    {
   
        _ASSERTE (ms.ullTotalVirtual == restricted_limit);
        if (memory_load != NULL)
            *memory_load = (uint32_t)((float)(ms.ullTotalVirtual - ms.ullAvailVirtual) * 100.0 / (float)ms.ullTotalVirtual);
        if (available_physical != NULL)
            *available_physical = ms.ullTotalVirtual;

        // Available page file isn't helpful when we are restricted by virtual memory
        // since the amount of memory we can reserve is less than the amount of
        // memory we can commit.
        if (available_page_file != NULL)
            *available_page_file = 0;
    }
    else
    {
   
        if (memory_load != NULL)
            *memory_load = ms.dwMemoryLoad;
        if (available_physical != NULL)
            *available_physical = ms.ullAvailPhys;
        if (available_page_file != NULL)
            *available_page_file = ms.ullAvailPageFile;
    }
}

分配量超过分配阈值的问题,这个是在GC初始化的时候回适当的分配阈值的上下限,当分配的内存超过阈值的上下限的时候也会触发GC的回收。
第0带的阈值下限位0,上线也为6MB左右
第1代的阈值下限位160KB,上限无限制
第二代的阈值下限为 256kb,上限无限制
第二代大对象阈值下限为3MB,上线无限制
至于系数,由于第0代区分服务器和工作战模式所以分别为(20,10以及9,20) 其余代
上下限以及12代大小对象的分别为(2,7 —1.2f,1.8f— 1.25f,4.5f)

1.停止其它线程切换到抢占模式,大致就是停止其它的线程不让其访问托管空间。

  FORCEINLINE_NONDEBUG void EnablePreemptiveGC()
    {
   
        LIMITED_METHOD_CONTRACT;

#ifndef DACCESS_COMPILE
        _ASSERTE(this == GetThread());
        _ASSERTE(m_fPreemptiveGCDisabled);
        // holding a spin lock in coop mode and transit to preemp mode will cause deadlock on GC
        _ASSERTE ((m_StateNC & Thread::TSNC_OwnsSpinLock) == 0);

#ifdef ENABLE_CONTRACTS_IMPL
        _ASSERTE(!GCForbidden());
        TriggersGC(this);
#endif

        // ------------------------------------------------------------------------
        //   ** WARNING ** WARNING ** WARNING ** WARNING ** WARNING ** WARNING **  |
        // ------------------------------------------------------------------------
        //
        //   DO NOT CHANGE THIS METHOD WITHOUT VISITING ALL THE STUB GENERATORS
        //   THAT EFFECTIVELY INLINE IT INTO THEIR STUBS
        //
        // ------------------------------------------------------------------------
        //   ** WARNING ** 
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值