stackalloc

stackalloc 关键字在堆栈上创建一个内存区域,并返回指向该内存开头的指针。当退出创建范围时,将自动删除堆栈分配的内存。

//Allocate 1024 bytes. This returns a pointer to the first byte.
byte* ptr = stackalloc byte[1024];

//Assign some values...
ptr[0] = 109;
ptr[1] = 13;
ptr[2] = 232;
...

用于不安全的上下文。

与 C#中的所有指针一样,没有对读取和赋值的边界检查。超出分配内存范围的读取将产生不可预测的结果 - 它可能访问内存中的某个任意位置,或者可能导致访问冲突异常。

//Allocate 1 byte
byte* ptr = stackalloc byte[1];

//Unpredictable results...
ptr[10] = 1;
ptr[-1] = 2;

当退出创建范围时,将自动删除堆栈分配的内存。这意味着你永远不应该返回使用 stackalloc 创建的内存,或者将其存储在范围的生命周期之外。

unsafe IntPtr Leak() {
    //Allocate some memory on the stack
    var ptr = stackalloc byte[1024];

    //Return a pointer to that memory (this exits the scope of "Leak")
    return new IntPtr(ptr);
}

unsafe void Bad() {
     //ptr is now an invalid pointer, using it in any way will have
     //unpredictable results. This is exactly the same as accessing beyond
     //the bounds of the pointer.
     var ptr = Leak();
}

stackalloc 只能在声明初始化变量时使用。以下是正确的:

byte* ptr;
...
ptr = stackalloc byte[1024];

备注:

stackalloc 应仅用于性能优化(用于计算或互操作)。这是因为:

  • 垃圾收集器不是必需的,因为内存是在堆栈而不是堆上分配的 - 一旦变量超出范围就释放内存
  • 在堆栈而不是堆上分配内存更快
  • 由于数据的位置,增加了 CPU 上缓存命中的可能性