在《C#12 In A Nutshell》一书中,作者写下了这样的代码:
UnsafeClass a = new UnsafeClass ("Christian Troy");
unsafe struct UnsafeUnicodeString
{
public short Length;
public fixed byte Buffer[30];
}
unsafe class UnsafeClass
{
UnsafeUnicodeString uus;
public UnsafeClass (string s)
{
uus.Length = (short)s.Length;
fixed (byte* p = uus.Buffer)
for (int i = 0; i < s.Length; i++)
p[i] = (byte) s[i];
}
}
然后他们提到
此示例中还使用了 fixed 关键字,将对象固定在包含缓冲区的堆上(该对象将是 UnsafeClass 的实例)
我不确定我是否理解他们的意思/他们在说什么。如果他们说的是a
,为什么a
需要固定。如果他们说的是uus
,为什么他们会说“将对象固定在堆上”,uus
应该在堆栈上,对吗?(仅限值类型)或者也许他们在谈论p
?但p
如果我理解正确的话,是在堆栈上?
当我们
fixed
以这种方式使用时,缓冲区被固定在它所在的位置;这可能在堆栈上(在这种情况下实际上没有任何变化,尽管仍可观察到步骤),但在这种情况下uus.Buffer
指的是对象的字段。我们最终得到的是一个特殊的局部变量,它是指向堆(实例)上对象内部地址的“内部指针” 。这里的任何时候都不在堆栈上 - 只是加载了字段的地址(在特定对象上)。UnsafeClass
UnsafeUnicodeString
正是这些特殊的局部变量间接地固定了对象;GC 需要在堆栈上定位所有这些特殊的局部变量(激活 GC 时),并确保更宽的对象被视为固定的。
a
需要固定该对象(指向的同一个对象) ,因为数据就在那里- 作为该对象内的字段。如果没有固定,指针p
就会指向错误的位置 - 这是一个非托管指针,并且在移动期间 GC 不会调整非托管指针(重点是您应该帮助 GC不要移动它们,这就是我们在这里所做的)。