4

我发现一个博客条目表明有时 c# 编译器可能决定将数组放在堆栈而不是堆上:

通过堆栈分配提高性能(.NET 内存管理:第 2 部分)

这个人声称:

编译器有时也会决定自己把东西放在堆栈上。我用 TestStruct2 做了一个实验,我给它分配了一个不安全和正常的上下文。在不安全的上下文中,数组被放在堆上,但在正常的上下文中,当我查看内存时,数组实际上是在堆栈上分配的。

有人可以确认吗?
我试图重复他的例子,但每次我尝试数组都分配在堆上。

如果 c# 编译器可以在不使用 'unsafe' 关键字的情况下做到这一点,我对它特别感兴趣。我有一个代码正在处理许多小字节数组(8-10 个字节长),因此为每个新字节使用堆 [...] 是浪费时间和内存(尤其是堆上的每个对象都有 8 个字节的开销垃圾收集器需要)。

编辑:我只想描述为什么它对我很重要:
我正在编写与 Gemalto.NET 智能卡通信的库,它可以在其中运行 .net 代码。当我调用一个返回某些东西的方法时,智能卡返回 8 个字节来描述我返回值的确切类型。这 8 个字节是通过使用 md5 哈希和一些字节数组连接计算得出的。
问题是,当我有一个我不知道的数组时,我必须扫描应用程序中加载的所有程序集中的所有类型,并且对于每个类型,我必须计算这 8 个字节,直到找到相同的数组。
我不知道找到类型的其他方法,所以我试图尽可能加快速度。

4

3 回答 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);
}

如果您尝试将哈希与类型匹配,那么最好的主意似乎是使用字典进行快速查找。在这种情况下,您可以在启动时加载所有相关类型,如果这导致程序启动变得太慢,您可能需要考虑在第一次使用每种类型时缓存它们。

于 2009-07-17T14:10:37.947 回答
2

从你的行:

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

就个人而言,我更感兴趣的是在代码的不同部分可以重用的地方分配一个备用缓冲区(在处理同一个块时)。然后你就不用担心任何创建/GC。在大多数情况下(缓冲区用于非常谨慎的操作)带有暂存缓冲区,您甚至可以始终假设它是“全部属于您的” - 即每个需要它的方法都可以假设它们可以从零开始写入。

我在一些二进制序列化代码中使用这种单缓冲区方法(在编码数据时);这对性能有很大的推动作用。在我的例子中,我在序列化层之间传递了一个“上下文”对象(它封装了暂存缓冲区、输出流(带有一些额外的本地缓冲)和一些其他奇怪的东西)。

于 2009-07-14T08:00:52.507 回答
1

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

我看不到您所指的文章中另有说明的地方。如果你想有一个堆栈分配的数组,你可以这样做:

decimal* stackAllocatedDecimals = stackalloc decimal[4];

就我个人而言,我不会打扰-您认为通过这种方法可以获得多少性能?

不过,这篇CodeProject 文章可能对您有用。

于 2009-07-14T07:37:51.977 回答