关注公众号,获取源码和学习文件
要了解这个问题,首先要知道。根对象实际上是通过GCInfo里面的存储位数获得的,而GCInfo 是RyuJit在编译IL代码为机器码的时候生成的。
首先就是获取到根对象,然后把根对象的所有引用的对象给它找出来呢
看一段代码:
#define go_through_object(mt,o,size,parm,start,start_useful,limit,exp) \
{ \
CGCDesc* map = CGCDesc::GetCGCDescFromMT((MethodTable*)(mt)); \
CGCDescSeries* cur = map->GetHighestSeries(); \
ptrdiff_t cnt = (ptrdiff_t) map->GetNumSeries(); \
\
if (cnt >= 0) \
{ \
CGCDescSeries* last = map->GetLowestSeries(); \
uint8_t** parm = 0; \
do \
{ \
assert (parm <= (uint8_t**)((o) + cur->GetSeriesOffset())); \
parm = (uint8_t**)((o) + cur->GetSeriesOffset()); \
uint8_t** ppstop = \
(uint8_t**)((uint8_t*)parm + cur->GetSeriesSize() + (size));\
if (!start_useful || (uint8_t*)ppstop > (start)) \
{ \
if (start_useful && (uint8_t*)parm < (start)) parm = (uint8_t**)(start);\
while (parm < ppstop) \
{ \
{exp} \
parm++; \
} \
} \
cur--; \
\
} while (cur >= last); \
}
}
宏
go_through_object
就是获取到根对象所引用的所有object 然后把它给遍历出来。
这个遍历过程是怎么样的呢?
代码说话
首先它,通过MethodTable实例化一个GCDESC。这个结构体里面不包含任何字段,只是函数操作。下面来了。
GetHighestSeries():这个函数把methodtable的地址前移24字节。为啥是24因为它首先把PTR_size_t实际上就是先挪8字节。然后再把PTR_CGCDescSeries减去1,因为PTR_CGCDescSeries实际上包含了两个size_t ,那么实际上就是16字节。8+16刚好24字节。
GetNumSeries():这个函数是把methodtable地址值前挪8位。然后获取它里面的值。这个里面的值表示当前根对象引用了几个对象。也就是引用对象的个数。
GetNumSeries(): 这个函数是把objectheader的指针加上objheader的长度,以便获取到methodtable的地址。也就是objecft对象的地址。
在cur >= last之前,会一直遍历所引用的对象,把它完全标记为止。如果没有标记完,会一直do while循环查找。
查找一个跟对象的步骤实际上就这么多。但是呢,还得验证下,口说无凭嘛。
using System;
namespace KongZhiTai
{
public class Ceshi
{
public int Id;
public Ceshi Prev;
public Ceshi Next;
public Ceshi(int id)
{
Id = id;
}
public void SetNetxt(Ceshi ceshi)
{
ceshi.Prev = this;
ceshi.Next = ceshi;
}
}
class Program
{
static void Main(string[] args)
{
Ceshi ceshi = new Ceshi(3333);
ceshi.SetNetxt(ceshi);
Console.WriteLine(ceshi);
}
}
}
看上面的C#代码。观察CeShi类的实例ceshi。