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
但是等等 !
如果我没有弄错的话,这就是实际的代码,那就是从那里开始拿那些static
, local
和parameters
!
那么为什么写这个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]
现在有更复杂的角落案例,考虑数组/对象访问。