使用不安全的C#和内存堆栈分配的反常行为

5

我正在尝试使用C#的不安全功能:http://ideone.com/L9uwZ5

我知道,在C#中这种方法是最差的,我想承认一下,在主题中有一些信息。看看“perversion”这个词。

我想以纯C的方式(甚至没有C++)在C#中实现快速排序。这可能有点疯狂,但我只是想深入了解不安全的C#的可能性。

我一直试图使用stackalloc运算符。我知道它是从堆栈而不是堆中分配内存,这就是为什么我的程序执行失败的原因。

但是当我没有在程序中看到任何异常/错误时,我感到困惑。

  • 为什么我没有收到任何明确的异常/错误?

另外,正如您所看到的代码的注释部分:

struct Header
{
    internal int* data;
};

Header* object_header = stackalloc Header[sizeof(Header)];
object_header->data = stackalloc int[length];

我无法使用最后一行编译它。C#编译器告诉我,在这个表达式stackalloc中不能使用。为什么呢?数据是int*类型,那么为什么在这里出现错误?

我只想使用堆栈帧而不是使用堆。

我知道还有另一种方法,但那是从堆中分配的。

int*[] data = new int*[length * sizeof(int)];
IntPtr result = Marshal.AllocHGlobal(Marshal.SizeOf(length * sizeof(int)));
Marshal.WriteInt32(result, 0);
for(int i = 0; i < length * sizeof(int); i++) d[i] = (int*)result;

例如,但这不是堆栈分配。
在C#语言中,我如何使用堆栈分配和纯C风格的语法明确解决我的反常任务。
我知道C#并不是为此而创建的,这样的功能很愚蠢,但主要问题不在于重要性,而在于这些功能。

请发布完整的错误信息,因为我希望它告诉我们为什么不能像那样使用。 - usr
@usr 看起来你没有仔细阅读我的主题 :) 主要问题是:“但当我在程序中没有看到任何异常/错误时,我感到困惑。” 我没有收到任何错误,只是执行被取消而没有任何错误报告。 - Secret
你说:“C#编译器告诉我,在这个表达式中不能使用stackalloc。” 这不是你的主要问题吗? - usr
2个回答

5

Marc 展示了一个解决方法,我会尝试解释为什么需要这样做。你实际上正在编写非托管代码,但该方法仍然是托管方法。它从 IL 编译为机器代码,垃圾回收器将搜索其堆栈帧和 CPU 寄存器以查找对象引用。

Jitter 在编译方法时执行了两个重要的任务。一个很明显且高度可见,将 IL 翻译成机器代码。但另一个非常重要的任务却完全不可见,它生成了方法的元数据。它可以显示堆栈帧的哪些部分包含对象引用,以及哪些部分存储指针和值类型值。还可以在代码的哪些点,CPU 寄存器将存储对象引用。同样,在方法代码的哪个点,对象引用超出范围。GC.KeepAlive() 的原因是,它是一种产生零代码的非常独特的方法。

垃圾回收器需要该表格来可靠地查找对象引用。但是,此表格只有一个间接级别。它可以描述分配给 object_header 的堆栈空间,并将指针和指向的堆栈区域标记为“不要扫描对象引用”。它无法描述直接分配给 object_header->data 的堆栈空间块。它没有额外的间接性来将堆栈细分为较小的部分并描述 Header。使用虚拟局部变量解决了该问题。


3

stackalloc 想要分配给一个变量。下面的代码可以工作,但是在离开方法之前必须非常小心地取消分配 - 如果您让 object_header->data 指向堆栈中的某个位置: 会发生糟糕的事情:

    int* ptr = stackalloc int[length];
    object_header->data = ptr;

在规范中明确指出,它必须被分配给本地变量: local-variable-initializer:
...
stackalloc-initializer stackalloc-initializer:
stackalloc unmanaged-type [expression]

1
当函数成员返回时,您不需要释放堆栈分配。它会自动丢弃。请参阅:http://msdn.microsoft.com/en-us/library/aa664785(v=vs.71).aspx - Adrian Ciura
2
@AdrianCiura,我所说的“deallocating”指的是将“object_header->data”设置为其他内容;我会澄清。 - Marc Gravell

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接