繁体   English   中英

关于是否使用不安全代码和stackalloc固定的困惑

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM