How does the C# garbage collector find objects whose only reference is an interior pointer?(C# 垃圾收集器如何找到唯一引用是内部指针的对象?)
问题描述
据我所知,在 C# 中,ref
和 out
参数是通过仅传递相关值的原始地址来传递的.该地址可能是指向数组中的元素或对象中的字段的内部指针.
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);
}
}
在这种情况下,GC 需要找到对象的开头并将整个对象视为可达.它是如何做到的?它是否必须扫描整个堆以查找包含该指针的对象?这似乎很慢.
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.
没有 Microsoft 收集器的代码,但他们会使用类似于 Go 的跨度表的东西,该表可以快速查找不同的内存跨度",您可以键入指针的最高有效 X 位,具体取决于您选择的跨度有多大.从那里他们使用每个跨度包含 X 个相同大小的对象的事实来非常快速地找到您拥有的对象的标题.这几乎是一个 O(1) 操作.显然,Microsoft 堆会有所不同,因为它是按顺序分配的,不考虑对象大小,但它们将具有某种 O(1) 查找结构.
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;
}
请注意,.NET 垃圾收集器是一个复制收集器,因此每当在垃圾收集周期中移动对象时,都需要更新托管/内部指针.GC 将根据 JIT 时已知的方法参数知道每个堆栈帧的堆栈内部指针在哪里.
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# 垃圾收集器如何找到唯一引用是内部指针的对象?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!
本文标题为:C# 垃圾收集器如何找到唯一引用是内部指针的对象?


- 输入按键事件处理程序 2022-01-01
- C#MongoDB使用Builders查找派生对象 2022-09-04
- 如何用自己压缩一个 IEnumerable 2022-01-01
- WebMatrix WebSecurity PasswordSalt 2022-01-01
- Web Api 中的 Swagger .netcore 3.1,使用 swagger UI 设置日期时间格式 2022-01-01
- 带有服务/守护程序应用程序的 Microsoft Graph CSharp SDK 和 OneDrive for Business - 配额方面返回 null 2022-01-01
- C# 中多线程网络服务器的模式 2022-01-01
- MoreLinq maxBy vs LINQ max + where 2022-01-01
- 在哪里可以找到使用中的C#/XML文档注释的好例子? 2022-01-01
- 良好实践:如何重用 .csproj 和 .sln 文件来为 CI 创建 2022-01-01