[英]Confusion on whether to use fixed with unsafe code and stackalloc
我在下面有一段代码,只有一行注释掉了。 CreateArray
方法中发生的事情与注释掉的行相同。 我的问题是为什么当b->ArrayItems = d
被取消注释时它会起作用,但是当注释掉时返回垃圾? 我不认为我必须“修复”任何东西,因为所有信息都是不受管理的。 这个假设是不正确的?
class Program
{
unsafe static void Main(string[] args)
{
someInstance* b = stackalloc someInstance[1];
someInstance* d = stackalloc someInstance[8];
b->CreateArray();
// b->ArrayItems = d;
*(b->ArrayItems)++ = new someInstance() { IntConstant = 5 };
*(b->ArrayItems)++ = new someInstance() { IntConstant = 6 };
Console.WriteLine((b)->ArrayItems->IntConstant);
Console.WriteLine(((b)->ArrayItems - 1)->IntConstant);
Console.WriteLine(((b)->ArrayItems - 2)->IntConstant);
Console.Read();
}
}
public unsafe struct someInstance
{
public someInstance* ArrayItems;
public int IntConstant;
public void CreateArray()
{
someInstance* d = stackalloc someInstance[8];
ArrayItems = d;
}
}
我的问题是为什么当行被取消注释时它会起作用,但在注释掉时返回垃圾。
注释行是掩盖 CreateArray引起的错误的原因。 评论它暴露了这个bug。 但无论如何,这个bug都存在。
正如规范明确指出:
在该函数成员返回时,将自动丢弃在执行函数成员期间创建的所有堆栈分配的内存块。
CreateArray函数分配一个块,存储指向块的指针,块被丢弃,现在你有一个指向垃圾块的指针。 您必须 永远不会存储指向stackalloc'd块的指针,以便在块变为无效后可以访问存储。 如果您需要存储对它的引用,Heap会分配块,并且在完成后记得取消分配它。
请记住,在不安全的代码中, 您需要完全了解托管内存模型的所有内容。 一切 。 如果您不了解托管内存的所有内容,请不要编写不安全的代码。
那就是说,让我们解决一下你似乎更大的困惑,那就是“什么时候需要修复内存来获取指针?” 答案很简单。 当且仅当它是可移动内存时,您必须修复内存。 修复将可移动存储器转换为不可移动的存储器; 这就是修复的目的 。
你只能拿一些不可移动的东西; 如果你取一个可移动的东西的地址然后移动那么显然地址是错误的。 您需要确保在获取其地址之前内存不会移动,并且您需要确保在再次移动后不再使用该地址。
Stackalloc在callstack上分配一些空间,当你向上移出当前的上下文级别时(例如,留下一个方法),该空间就会丢失。 你的问题是当stackalloc在一个方法中时,当你离开那个方法时,堆栈的那个区域就不再是你的了。
所以,如果你这样做:
foo()
{
stuff = stackalloc byte[1]
Do something with stuff
}
“stuff”只在foo中有效,一旦你离开foo,堆栈就会被收回,这意味着如果你这样做:
foo()
{
byte* allocate()
{
return stackalloc[1]
}
stuff = allocate()
do something with stuff
}
当你离开allocate方法时,allocate的返回值变成垃圾,这意味着“东西”从来没有任何意义。
您的假设部分正确,但错误理解。 以下是此MSDN页面的引用:
在不安全模式下,您可以在堆栈上分配内存,它不受垃圾回收的影响,因此不需要固定。 有关更多信息,请参阅stackalloc 。
有些语句会自动在堆栈上分配变量(即方法中的值类型),其他stackalloc
需要使用stackalloc
专门指定。
在方法结束后丢弃堆栈分配的内存,因此您的问题(请参阅Eric Lipperts回答,谁在我之前写了这个)。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.