GC根源误解?

我知道Roots是:

  • 静态字段
  • 方法参数
  • 当地的fielfs
  • f-queue还包含一个指向“即将被完成”的对象的指针
  • cpu寄存器<= ???

在此处输入图像描述

现在让我们谈谈寄存器。

他们可以包含的代码如下:

mov bx, 0034h ; bx = 52 (stored in 16 bits) mov cl, bl ; cl = lower 8-bits of bx mov eax, ecx call print_int 

但是等等

如果我没有弄错的话,这就是实际的代码,那就是从那里开始那些staticlocalparameters

那么为什么写这个TWICE呢? (或从另一个方向?)

为什么要写(例如)

  Foo f = new Foo(); **and also** mov bx, 0034h //<-------- represents the `f` address or something like that 

编辑

关于寄存器的问题来自这里: 在此处输入图像描述

在此处输入图像描述

考虑

 string sentence = ... int wordCount = sentence.Split(' ').Length; 

String.Split()生成一个数组,它必须保持可以访问此语句的(部分)。 但是没有指向它的变量或参数,优化器很可能将引用保留在寄存器中。

因此,CPU(地址)寄存器必须被视为根的一部分。

寄存器只临时保存变量的值。

例如,当您创建对象并将引用存储在变量中时:

 Foo f = new Foo(); 

发生的事情是调用构造函数,并返回对象的引用。 在此阶段,引用仅存在于寄存器中。 然后寄存器的内容被复制到变量中,所以现在引用存在于寄存器和变量中。 然后寄存器继续并用于其他内容,因此引用仅存在于变量中。


另请注意,不仅寄存器中当前的值是根。 每个线程都有自己的一组寄存器,当线程未运行时,这些寄存器会切换到内存,所有这些寄存器值集也都是根。

因为JIT编译器可能会优化某些部分而不使用堆栈,而是直接转到寄存器。

让我们进行方法调用,例如:

 object a = new object(), b = new object(), c = new object(); DoSomething(a, b, c); 

JIT编译器会尝试将尽可能多的参数放入寄存器rahter,而不是将它们推入堆栈。 在X86上本地构建的示例显示:

 00000082 push dword ptr [ebp-10h] 00000085 mov ecx,dword ptr [ebp-8] 00000088 mov edx,dword ptr [ebp-0Ch] 0000008b call dword ptr ds:[00742078h] 

现在有更复杂的角落案例,考虑数组/对象访问。