2

我有一个大小为 2 GB 的数组(填充了音频样本)。现在我想为该数组应用一个过滤器。这个过滤器生成的样本比输入源多 50%。所以现在我需要创建大小为 3 GB 的新数组。现在我给了 5 GB 的内存使用。但是如果这个过滤器只能在那个源数组上运行,并且只需要这个数组中的一些空间。问题:我可以在 C# 中分配一个内存,它可以在不创建第二个内存块的情况下调整大小,然后删除第一个内存块?我只是想,如果 PC 中的内存被划分为 4 kB 页面(或更多),那么为什么 C# 不能(?)使用那个好的特性呢?

4

2 回答 2

3

问题:我可以在 C# 中分配一个内存,它可以在不创建第二个内存块的情况下调整大小,然后删除第一个内存块?

不,您不能在 .NET 中调整数组的大小。如果要增加数组的大小,则必须创建一个更大的新数组并将现有数组中的所有数据复制到新数组中。

为了解决这个问题,您可以提供自己的“数组”实现,基于分配较小的内存块,但将其呈现为一个大的数据缓冲区。这方面的一个例子StringBuilder是基于字符块的实现,每个块都是一个单独的Char[]数组。

另一种选择是使用 P/Invoke 来访问低级内存管理功能,例如VirtualAlloc,它允许您提前保留内存页面。您需要在 64 位进程中执行此操作,因为 32 位进程的虚拟地址空间只有 4 GB。您可能还需要使用不安全的代码和指针

于 2012-08-07T08:58:49.727 回答
3

如果您的过滤器可以就地工作,只需在开始时多分配 50% 的空间。您只需要知道原始样本的实际长度。

如果该代码并不总是有效并且您不想事先消耗更多内存,您可以分配一半的原始数组(扩展数组)并检查您的访问与哪个部分相关:

byte[] myOriginalArray = new byte[2GB]; // previously allocated 

byte[] myExtensionArray = new byte[1GB]; // 50% of the original
for(... my processing code of the array ...)
{
  byte value = read(index);
  ... process the index and the value here
  store(index, value);
}

byte read(int index)
{
  if(index < 2GB) return myOriginalArray[index];
  return myExtensionArray[index - 2GB];
}

void store(int index, byte value)
{
   if(index < 2GB) myOriginalArray[index] = value;
   myExtensionArray[index - 2GB] = value;
}

您为对数组的每次访问添加索引检查和减法开销。对于某些情况,这也可以变得更聪明。例如,对于不需要访问扩展的部分,您可以使用更快的循环,对于需要写入扩展部分的部分,您可以使用较慢的版本(两个连续循环)。

于 2012-08-07T09:06:32.590 回答