C#垃圾收集器如何查找其唯一引用是内部指针的对象? [英] How does the C# garbage collector find objects whose only reference is an interior pointer?

查看:99
本文介绍了C#垃圾收集器如何查找其唯一引用是内部指针的对象?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在C#中,据我所知, ref out params是通过只传递raw相关价值的地址。该地址可能是一个内部指针,指向数组中的元素或对象内的字段。



如果发生垃圾回收,可能只有 / em>引用某个对象是通过这些内部指针之一,如下所示:

  using System; 

public class Foo
{
public int field;

public static void Increment(ref int x){
System.GC.Collect();
x = x + 1;
Console.WriteLine(x);
}

public static void Main()
{
Increment(ref new Foo()。field);




$ b $ p
$ b

在这种情况下,GC需要找到开始并将整个对象视为可访问的。它是如何做到的?它是否必须扫描整个堆寻找包含该指针的对象?这看起来很慢。

解决方案

垃圾收集器将有一种快速的方式来从托管的内部指针查找对象的开始。从那里它可以明显地标记对象为引用,当进行清理阶段。



没有Microsoft收集器的代码,但他们会使用类似于Go的跨度表可快速查找不同的跨度内存,根据您选择跨度的大小,您可以键入指针的最高有效X位。从那里他们使用这样一个事实,即每个跨度包含X个相同大小的物体,以便快速找到您所拥有的标题。这几乎是一个O(1)操作。显然,微软的堆将会有所不同,因为它是按顺序分配的,而不考虑对象的大小,但它们会有某种O(1)查找结构。

https://github.com/puppeh/gcc-6502/blob/master /libgo/runtime/mgc0.c

  // //请参阅span table以查找开始。 
//(手动插入MHeap_LookupMaybe副本)
k =(uintptr)obj>> PageShift;
x = k;
x - =(uintptr)runtime_mheap.arena_start>> PageShift;
s = runtime_mheap.spans [x];
if(s == nil || k< s-> start ||(const byte *)obj> = s-> limit || s-> state!= MSpanInUse)
返回false;
p =(byte *)((uintptr)s-> start<< PageShift);
if(s-> sizeclass == 0){
obj = p;
} else {
uintptr size = s-> elemsize;
int32 i =((const byte *)obj - p)/ size;
obj = p + i * size;
}

请注意,.NET垃圾收集器是一个复制收集器,所以托管/内部指针需要在垃圾收集周期中移动对象时进行更新。 GC会根据JIT时间已知的方法参数知道堆栈内部指针在每个堆栈帧中的位置。


In C#, ref and out params are, as far as I know, passed by passing only the raw address of the relevant value. That address may be an interior pointer to an element in an array or a field within an object.

If a garbage collection occurs, it's possible that the only reference to some object is through one of these interior pointers, as in:

using System;

public class Foo
{
    public int field;

    public static void Increment(ref int x) {
        System.GC.Collect();
        x = x + 1;
        Console.WriteLine(x);
    }

    public static void Main()
    {
        Increment(ref new Foo().field);
    }
}

In that case, the GC needs to find the beginning of the object and treat the entire object as reachable. How does it do that? Does it have to scan the entire heap looking for the object that contains that pointer? That seems slow.

解决方案

The garbage collector will have a fast way to find the start of an object from a managed interior pointer. From there it can obviously mark the object as "referenced" when doing the sweeping phase.

Don't have the code for the Microsoft collector but they would use something similar to Go's span table which has a fast lookup for different "spans" of memory which you can key on the most significant X bits of the pointer depending on how large you choose the spans to be. From there they use the fact that each span contains X number of objets of the same size to very quickly find the header of the one you have. It's pretty much an O(1) operation. Obviously the Microsoft heap will be different since it's allocated sequentially without regard for object size but they will have some sort of O(1) lookup structure.

https://github.com/puppeh/gcc-6502/blob/master/libgo/runtime/mgc0.c

// Otherwise consult span table to find beginning.
// (Manually inlined copy of MHeap_LookupMaybe.)
k = (uintptr)obj>>PageShift;
x = k;
x -= (uintptr)runtime_mheap.arena_start>>PageShift;
s = runtime_mheap.spans[x];
if(s == nil || k < s->start || (const byte*)obj >= s->limit || s->state != MSpanInUse)
    return false;
p = (byte*)((uintptr)s->start<<PageShift);
if(s->sizeclass == 0) {
    obj = p;
} else {
    uintptr size = s->elemsize;
    int32 i = ((const byte*)obj - p)/size;
    obj = p+i*size;
}

Note that the .NET garbage collector is a copying collector so managed/interior pointers need to be updated whenever the object is moved during a garbage collection cycle. The GC will be aware of where in the stack interior pointers are for each stack frame based on the method parameters known at JIT time.

这篇关于C#垃圾收集器如何查找其唯一引用是内部指针的对象?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆