C#编译器自己决定是否使用stackalloc吗?

4
我找到了一篇博客文章,其中提到C#编译器有时会决定将数组放在堆栈上而不是堆上: 通过堆栈分配来提高性能(.NET内存管理:第二部分) 这个人声称:
编译器有时也会自行决定将东西放在堆栈上。我用TestStruct2做了一个实验,在不安全的环境中分配它,在正常的环境中当我查看内存时,数组实际上已经被分配在堆栈上了。
有人可以证实吗?
我试图重复他的例子,但每次都尝试时,数组都是在堆上分配的。
如果C#编译器可以在不使用“unsafe”关键字的情况下进行这样的技巧,我对此特别感兴趣。我有一段代码,它正在处理许多小字节数组(长8-10字节),因此为每个新的byte[...]使用堆是时间和内存的浪费(特别是每个堆上的对象都需要8字节的开销,需要垃圾回收器)。 编辑:我只是想描述为什么这对我很重要:
我正在编写一个库,该库与Gemalto.NET智能卡通信,该卡可以在其中运行.net代码。当我调用返回某些内容的方法时,智能卡会返回8个字节,这些字节描述了返回值的确切类型。通过使用md5哈希和一些字节数组连接来计算这8个字节。
问题在于,当我有一个未知的数组时,我必须扫描应用程序中加载的所有程序集中的所有类型,并为每个类型计算这8个字节,直到找到相同的数组。
我不知道其他找到类型的方法,所以我正在尽可能加快速度。
3个回答

4

这篇文章的作者在此。

似乎不可能在非安全上下文中强制进行堆栈分配。这很可能是为了防止某些类型的堆栈溢出情况。

相反,我建议使用一个内存回收器类,它会根据需要分配字节数组,但也允许您在之后“归还”它们以供重用。只需保持未使用字节数组的堆栈,并在列表为空时分配新的字节数组即可。

Stack<Byte[]> _byteStack = new Stack<Byte[]>();

Byte[] AllocateArray()
{
Byte[] outArray;
if (_byteStack.Count > 0)
  outArray = _byteStack.Pop(); 
else
  outArray = new Byte[8];
return outArray;
}

void RecycleArray(Byte[] inArray)
{
  _byteStack.Push(inArray);
}

如果你想将哈希值与类型进行匹配,最好的方法是使用字典进行快速查找。在这种情况下,你可以在启动时加载所有相关类型,如果这导致程序启动变得太慢,你可以考虑在每次使用类型时首次缓存它们。

2
来自未来的提示:这个答案在它被写出来时是正确的,但现在已经不再适用了。你现在可以(C# 7.2及更高版本)在非unsafe上下文中使用Span<>ReadOnlySpan<>来进行stackalloc操作。 - starikcetin

2

根据你的描述:

我有一个可以处理许多小字节数组(8-10个字节长)的代码。

个人而言,我更喜欢在某个地方分配一个备用缓冲区,以便你的代码的不同部分可以重复使用它(同时处理相同的块)。这样你就不需要担心创建和GC。在大多数情况下(其中缓冲区用于非常离散的操作),使用临时缓冲区,你甚至可以始终假设它是“完全属于你自己”的 - 即每个需要它的方法都可以假定它们可以从零开始写入。

我在某些二进制序列化代码中使用这种单缓冲区方法(在编码数据时);它对性能有很大提升。在我的情况下,我在序列化的各个层之间传递一个“上下文”对象(封装了临时缓冲区、输出流(带有一些附加的本地缓冲区)和一些其他奇怪的东西)。


因为这种类型的扫描可以轻松地进行流水线处理,所以我编写了扩展方法,只分配了一次此数组并使用yield return。感谢您的建议 :-) - SeeR

1

System.Array(表示数组的类)是引用类型,存储在堆上。如果您使用不安全代码,则只能在堆栈上拥有数组。

我看不到您所提到的文章中有其他说明。如果您想要一个堆栈分配的数组,可以这样做:

decimal* stackAllocatedDecimals = stackalloc decimal[4];

个人而言,我觉得不值得麻烦——你认为这种方法能带来多少性能提升呢?

不过,这篇CodeProject文章或许对你有用。


1
在紧密循环中,性能提升可能非常大。此外,避免重复的堆分配将防止堆碎片化。这与使用 StringBuilder 而不是反复创建需要由垃圾回收器清理的 String 类的新不可变实例的原因非常相似。 - Rick Minerich
1
@Rick- 当然,这可能会大大提高性能- 除非您对应用程序进行分析,否则您不知道这是否是性能问题的根本原因。 - RichardOD

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