C# `stackalloc` 关键字的实际使用

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/785226/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-05 01:03:05  来源:igfitidea点击:

Practical use of `stackalloc` keyword

c#keywordstackalloc

提问by Groo

Has anyone ever actually used stackallocwhile programming in C#? I am aware of what is does, but the only time it shows up in my code is by accident, because Intellisense suggests it when I start typing static, for example.

有没有人stackalloc在 C# 编程时实际使用过?我知道是做什么的,但它出现在我的代码中的唯一一次是偶然的,因为智能感知在我开始输入时会建议它static,例如。

Although it is not related to the usage scenarios of stackalloc, I actually do a considerable amount of legacy interop in my apps, so every now and then I could resort to using unsafecode. But nevertheless I usually find ways to avoid unsafecompletely.

虽然它与 的使用场景无关,但stackalloc我实际上在我的应用程序中做了相当多的遗留互操作,所以我时不时会求助于使用unsafe代码。但尽管如此,我通常会找到unsafe完全避免的方。

And since stack size for a single thread in .Net is ~1Mb (correct me if I'm wrong), I am even more reserved from using stackalloc.

而且由于 .Net 中单个线程的堆栈大小为 ~1Mb(如果我错了,请纠正我),因此我更不愿意使用stackalloc.

Are there some practical cases where one could say: "this is exactly the right amount of data and processing for me to go unsafe and use stackalloc"?

是否有一些实际案例可以说:“这正是我不安全和使用的正确数量的数据和处理stackalloc”?

采纳答案by Pop Catalin

The sole reason to use stackallocis performance (either for computations or interop). By using stackallocinstead of a heap allocated array, you create less GC pressure (the GC needs to run less), you don't need to pin the arrays down, it's faster to allocate than a heap array, an it is automatically freed on method exit (heap allocated arrays are only deallocated when GC runs). Also by using stackallocinstead of a native allocator (like malloc or the .Net equivalent) you also gain speed and automatic deallocation on scope exit.

使用的唯一原因stackalloc是性能(用于计算或互操作)。通过使用stackalloc而不是堆分配的数组,您可以减少 GC 压力(GC 需要运行更少),您不需要固定数组,分配比堆数组更快,并且它会在方上自动释放退出(堆分配的数组仅在 GC 运行时解除分配)。此外,通过使用stackalloc本机分配器(如 malloc 或 .Net 等价物),您还可以在范围退出时获得速度和自动解除分配。

Performance wise, if you use stackallocyou greatly increase the chance of cache hits on the CPU due to the locality of data.

性能方面,如果使用stackalloc,由于数据的局部性,会大大增加 CPU 上缓存命中的机会。

回答by Brian Rasmussen

stackallocis only relevant for unsafe code. For managed code you can't decide where to allocate data. Value types are allocated on the stack per default (unless they are part of a reference type, in which case they are allocated on the heap). Reference types are allocated on the heap.

stackalloc仅与不安全代码相关。对于托管代码,您无决定在何处分配数据。默认情况下,值类型在堆栈上分配(除非它们是引用类型的一部分,在这种情况下,它们在堆上分配)。引用类型在堆上分配。

The default stack size for a plain vanilla .NET application is 1 MB, but you can change this in the PE header. If you're starting threads explicitly, you may also set a different size via the constructor overload. For ASP.NET applications the default stack size is only 256K, which is something to keep in mind if you're switching between the two environments.

普通 vanilla .NET 应用程序的默认堆栈大小为 1 MB,但您可以在 PE 标头中更改此大小。如果您明确启动线程,您还可以通过构造函数重载设置不同的大小。对于 ASP.NET 应用程序,默认堆栈大小仅为 256K,如果您在两种环境之间切换,请记住这一点。

回答by Jim Arnold

I have used stackalloc to allocate buffers for [near] realtime DSP work. It was a very specific case where performance needed to be as consistent as possible. Note there is a difference between consistency and overall throughput - in this case I wasn't concerned with heap allocations being too slow, just with the non determinism of garbage collection at that point in the program. I wouldn't use it in 99% of cases.

我已经使用 stackalloc 为 [near] 实时 DSP 工作分配缓冲区。这是一个非常特殊的案例,性能需要尽可能保持一致。请注意,一致性和整体吞吐量之间存在差异 - 在这种情况下,我不关心堆分配太慢,只是在程序中的那个点垃圾收集的不确定性。我不会在 99% 的情况下使用它。

回答by anth

Stackalloc initialization of spans. In previous versions of C#, the result of stackalloc could only be stored into a pointer local variable. As of C# 7.2, stackalloc can now be used as part of an expression and can target a span, and that can be done without using the unsafe keyword. Thus, instead of writing

跨度的 Stackalloc 初始化。在以前的 C# 版本中,stackalloc 的结果只能存储到指针局部变量中。从 C# 7.2 开始,stackalloc 现在可以用作表达式的一部分并且可以定位到跨度,并且可以在不使用 unsafe 关键字的情况下完成。因此,而不是写

Span<byte> bytes;
unsafe
{
  byte* tmp = stackalloc byte[length];
  bytes = new Span<byte>(tmp, length);
}

You can write simply:

你可以简单地写:

Span<byte> bytes = stackalloc byte[length];

This is also extremely useful in situations where you need some scratch space to perform an operation, but want to avoid allo-cating heap memory for relatively small sizes

这在您需要一些暂存空间来执行操作但又希望避免为相对较小的大小分配堆内存的情况下也非常有用

Span<byte> bytes = length <= 128 ? stackalloc byte[length] : new byte[length];
... // Code that operates on the Span<byte>

Source:C# - All About Span: Exploring a New .NET Mainstay

来源:C# - 关于 Span:探索新的 .NET 支柱

回答by fjch1997

There are some great answers in this question but I just want to point out that

这个问题有一些很好的答案,但我只想指出

Stackalloc can also be used to call native APIs

Stackalloc 也可用于调用原生 API

Many native functions requires the caller to allocate a buffer to get the return result. For example, the CfGetPlaceholderInfofunction in cfapi.hhas the following signature.

许多原生函数需要调用者分配一个缓冲区来获取返回结果。例如,CfGetPlaceholderInfo函数cfapi.h具有以下签名。

HRESULT CfGetPlaceholderInfo(
HANDLE                    FileHandle,
CF_PLACEHOLDER_INFO_CLASS InfoClass,
PVOID                     InfoBuffer,
DWORD                     InfoBufferLength,
PDWORD                    ReturnedLength);

In order to call it in C# through interop,

为了通过互操作在 C# 中调用它,

[DllImport("Cfapi.dll")]
public static unsafe extern HResult CfGetPlaceholderInfo(IntPtr fileHandle, uint infoClass, void* infoBuffer, uint infoBufferLength, out uint returnedLength);

You can make use of stackalloc.

您可以使用 stackalloc。

byte* buffer = stackalloc byte[1024];
CfGetPlaceholderInfo(fileHandle, 0, buffer, 1024, out var returnedLength);