Gro*_*roo 121 c# keyword stackalloc
有没有人stackalloc在C#编程时实际使用过?我知道它的作用是什么,但它出现在我的代码中的唯一一次是偶然的,因为Intellisense在我开始输入时建议它static,例如.
虽然它与使用场景无关,但stackalloc我实际上在我的应用程序中做了大量的遗留互操作,因此我偶尔会使用unsafe代码.但是,我通常会找到unsafe完全避免的方法.
而且由于.Net中单个线程的堆栈大小约为1Mb(如果我错了,请纠正我),我使用时更加保留stackalloc.
是否有一些实际案例可以说:"这对我来说是不正确的数据和处理不安全和使用stackalloc"?
Pop*_*lin 132
使用的唯一原因stackalloc是性能(用于计算或互操作).通过使用stackalloc而不是堆分配的数组,您可以创建更少的GC压力(GC需要运行更少),您不需要固定数组,分配比堆数组更快,它会自动释放方法exit(堆积分配的数组仅在GC运行时释放).此外,通过使用stackalloc而不是本机分配器(如malloc或.Net等效项),您还可以在范围退出时获得速度和自动释放.
性能方面,如果您使用它stackalloc会大大增加由于数据的位置而导致CPU上的缓存命中的可能性.
Jim*_*old 35
我已经使用stackalloc为[近]实时DSP工作分配缓冲区.这是一个非常具体的案例,其中性能需要尽可能一致.请注意,一致性和总吞吐量之间存在差异 - 在这种情况下,我并不关心堆分配太慢,只是在程序中该点的垃圾收集的非确定性.我不会在99%的情况下使用它.
Bri*_*sen 24
stackalloc仅适用于不安全的代码.对于托管代码,您无法决定在何处分配数据.默认情况下,值类型在堆栈上分配(除非它们是引用类型的一部分,在这种情况下,它们在堆上分配).引用类型在堆上分配.
普通vanilla .NET应用程序的默认堆栈大小为1 MB,但您可以在PE标头中更改此值.如果您明确地启动线程,您还可以通过构造函数重载设置不同的大小.对于ASP.NET应用程序,默认堆栈大小仅为256K,如果您在两个环境之间切换,请记住这一点.
ant*_*nth 11
范围的Stackalloc初始化。在早期版本的C#中,stackalloc的结果只能存储在指针局部变量中。从C#7.2开始,现在可以将stackalloc用作表达式的一部分,并且可以将其作为目标范围,并且可以在不使用unsafe关键字的情况下完成此操作。因此,与其写作
Span<byte> bytes;
unsafe
{
byte* tmp = stackalloc byte[length];
bytes = new Span<byte>(tmp, length);
}
Run Code Online (Sandbox Code Playgroud)
您可以简单地编写:
Span<byte> bytes = stackalloc byte[length];
Run Code Online (Sandbox Code Playgroud)
这在需要一些暂存空间来执行操作但又希望避免为较小的内存分配堆内存的情况下非常有用
Span<byte> bytes = length <= 128 ? stackalloc byte[length] : new byte[length];
... // Code that operates on the Span<byte>
Run Code Online (Sandbox Code Playgroud)
Ton*_*Nam 11
回答晚了,但我相信仍然有帮助。
我来到这个问题时,仍然对性能差异感到好奇,因此我创建了以下基准测试(使用 BenchmarkDotNet NuGet Package):
[MemoryDiagnoser]
[Orderer(SummaryOrderPolicy.FastestToSlowest)]
[RankColumn]
public class Benchmark1
{
//private MemoryStream ms = new MemoryStream();
static void FakeRead(byte[] buffer, int start, int length)
{
for (int i = start; i < length; i++)
buffer[i] = (byte) (i % 250);
}
static void FakeRead(Span<byte> buffer)
{
for (int i = 0; i < buffer.Length; i++)
buffer[i] = (byte) (i % 250);
}
[Benchmark]
public void AllocatingOnHeap()
{
var buffer = new byte[1024];
FakeRead(buffer, 0, buffer.Length);
}
[Benchmark]
public void ConvertingToSpan()
{
var buffer = new Span<byte>(new byte[1024]);
FakeRead(buffer);
}
[Benchmark]
public void UsingStackAlloc()
{
Span<byte> buffer = stackalloc byte[1024];
FakeRead(buffer);
}
}
Run Code Online (Sandbox Code Playgroud)
这就是结果
| Method | Mean | Error | StdDev | Rank | Gen 0 | Allocated |
|----------------- |---------:|---------:|---------:|-----:|-------:|----------:|
| UsingStackAlloc | 704.9 ns | 13.81 ns | 12.91 ns | 1 | - | - |
| ConvertingToSpan | 755.8 ns | 5.77 ns | 5.40 ns | 2 | 0.0124 | 1,048 B |
| AllocatingOnHeap | 839.3 ns | 4.52 ns | 4.23 ns | 3 | 0.0124 | 1,048 B |
Run Code Online (Sandbox Code Playgroud)
该基准测试表明 usingstackalloc是最快的解决方案,而且它不使用任何分配!如果您对如何使用 NuGet Package BenchmarkDotNet 感到好奇,请观看此视频。
这个问题有一些很好的答案,但我只想指出
Stackalloc也可用于调用本机API
许多本机函数需要调用者分配缓冲区来获取返回结果。例如,CfGetPlaceholderInfo函数cfapi.h具有以下签名。
HRESULT CfGetPlaceholderInfo(
HANDLE FileHandle,
CF_PLACEHOLDER_INFO_CLASS InfoClass,
PVOID InfoBuffer,
DWORD InfoBufferLength,
PDWORD ReturnedLength);
Run Code Online (Sandbox Code Playgroud)
为了通过互操作在C#中调用它,
[DllImport("Cfapi.dll")]
public static unsafe extern HResult CfGetPlaceholderInfo(IntPtr fileHandle, uint infoClass, void* infoBuffer, uint infoBufferLength, out uint returnedLength);
Run Code Online (Sandbox Code Playgroud)
您可以使用 stackalloc。
byte* buffer = stackalloc byte[1024];
CfGetPlaceholderInfo(fileHandle, 0, buffer, 1024, out var returnedLength);
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
21430 次 |
| 最近记录: |