.Net GC从空闲列表里面分配对象
创始人
2025-07-02 16:11:42
0

1.前言

空闲列表(free_list)实质上是GC经过垃圾回收之后形成的碎片空间,它的空间可以进行重新分配新的对象。本篇看下它的重新分配过程。

2.概述

当进行一个对象分配的时候,如果是慢速分配(JIT_New)的时候,它会查找空闲列表里面是否有足够的空间来分配这个对象。如果有就把这个对象放到空闲列表里面去。

CLR堆栈如下:

>  WKS::gc_heap::a_fit_free_list_p  C++
   WKS::gc_heap::soh_try_fit  C++
   WKS::gc_heap::allocate_soh  C++
   WKS::gc_heap::try_allocate_more_space  C++
   WKS::gc_heap::allocate_more_space  C++
   WKS::gc_heap::allocate  C++
   WKS::GCHeap::Alloc  C++
   Alloc  C++
   AllocateObject  C++
   JIT_New  C++
//此处省略一万行
   RtlUserThreadStart()  未知

着重看下这个a_fit_free_list_p函数,它就是进行空闲列表分配,关键代码如下:

BOOL gc_heap::a_fit_free_list_p (int gen_number,
                                 size_t size,
                                 alloc_context* acontext,
                                 uint32_t flags,
                                 int align_const)
{
    BOOL can_fit = FALSE;
    //获取当前收集代地址
    generation* gen = generation_of (gen_number);
    //获取当前收集代 空闲列表一直
    allocator* gen_allocator = generation_allocator (gen);
    //遍历冫空闲列表里面的bucket,找到何时的空间存储对象
    for (unsigned int a_l_idx = gen_allocator->first_suitable_bucket(size); a_l_idx < gen_allocator->number_of_buckets(); a_l_idx++)
    {
        //索引的空闲列表的头部指针
        uint8_t* free_list = gen_allocator->alloc_list_head_of (a_l_idx);
        uint8_t* prev_free_item = 0;
        //如果获取到的空闲列表空间不为0
        while (free_list != 0)
        {
            //获取当前索引空闲了free_list里面bucket的长度
            size_t free_list_size = unused_array_size (free_list);
           //如果需要分配对象长度小于free_lis里面获取的长度,那么表示对象可以放入空闲列表
            if ((size + Align (min_obj_size, align_const)) <= free_list_size)
            {
                //unlink,断开链接。意思是从空闲列表里面把空间拿出来,因为它操作的是链表。
                // 把获取到的free_lsit的bucket长度从free_lsit链表里面拿掉,也就是个链表操作
                gen_allocator->unlink_item (a_l_idx, free_list, prev_free_item, FALSE);
                //计算出对象需要的空间也就是参数size,最终需要分配的长度
                size_t limit = limit_from_size (size, flags, free_list_size, gen_number, align_const);
                //收集代静态数据new_allocation减去对象最终分配空间大小
                dd_new_allocation (dynamic_data_of (gen_number)) -= limit;
                //空闲列表头部指针+对象占用空间大小,指向的是剩余的空间地址
                uint8_t*  remain = (free_list + limit);
                // 当前代的空闲列表大小减去分配对象的大小,剩余值remain_size
                size_t remain_size = (free_list_size - limit);
                //如果剩余值,大于或者等于一个空闲列表的大小
                if (remain_size >= Align(min_free_list, align_const))
                {
                   //重新把它作为空闲列表,放入free_list的bucket里面去
                    make_unused_array (remain, remain_size);
                    gen_allocator->thread_item_front (remain, remain_size);
                    assert (remain_size >= Align (min_obj_size, align_const));
                }
                else  //如果剩余值小于
                {
                    //这里直接把剩余值给分配对象大小得了,也就是上面计算的分配对象大小+剩余的空间
                    limit += remain_size;
                }
                //代的空闲空间减去对象需要的空间 
                generation_free_list_space (gen) -= limit;
                assert ((ptrdiff_t)generation_free_list_space (gen) >= 0);
                //把alloc_context指向计算的空间,对象就分配到alloc_context指向的地址
                adjust_limit_clr (free_list, limit, size, acontext, flags, 0, align_const, gen_number);


                can_fit = TRUE;
                goto end;
            }         
        }
    }
end:
    return can_fit;
}

以上整体的思路是

1.先找到当前垃圾回收的代
2.通过这个代找到次代的空闲列表
3.遍历循环空闲列表里的number_of_buckets,以找到合适的空间放置需要分配的对象
4.如果找到了此空间,就设置alloc_context指向此空间。对象分配就通过alloc_context来分配。

它这个整体上是操作空闲列表管理类,然后通过空闲列表管理类给对象分配空间。

相关内容

热门资讯

PHP新手之PHP入门 PHP是一种易于学习和使用的服务器端脚本语言。只需要很少的编程知识你就能使用PHP建立一个真正交互的...
网络中立的未来 网络中立性是什... 《牛津词典》中对“网络中立”的解释是“电信运营商应秉持的一种原则,即不考虑来源地提供所有内容和应用的...
各种千兆交换机的数据接口类型详... 千兆交换机有很多值得学习的地方,这里我们主要介绍各种千兆交换机的数据接口类型,作为局域网的主要连接设...
粉嫩如何诠释霸道 东芝M805... “霸道粉”是个什么玩意东芝M805拿过来的时候,笔者扑哧笑了,不是笑这款笔记本,而是笑这款产品的颜色...
什么是大数据安全 什么是大数据... 在《为什么需要大数据安全分析》一文中,我们已经阐述了一个重要观点,即:安全要素信息呈现出大数据的特征...
如何利用交换机和端口设置来管理... 在网络管理中,总是有些人让管理员头疼。下面我们就将介绍一下一个网管员利用交换机以及端口设置等来进行D...
全面诠释网络负载均衡 负载均衡的出现大大缓解了服务器的压力,更是有效的利用了资源,提高了效率。那么我们现在来说一下网络负载...
如何允许远程连接到MySQL数... [[277004]]【51CTO.com快译】默认情况下,MySQL服务器仅侦听来自localhos...
30分钟搞定iOS自定义相机 最近公司的项目中用到了相机,由于不用系统的相机,UI给的相机切图,必须自定义才可以。就花时间简单研究...
Intel将Moblin社区控... 本周二,非营利机构Linux基金会宣布,他们将担负起Moblin社区的管理工作,而这之前,Mobli...