【问题标题】:Resizing big arrays调整大数组的大小
【发布时间】:2012-08-07 08:53:52
【问题描述】:

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

【问题讨论】:

  • 不相关,但要存储在内存中的内容很多 - 您可能会遇到其他问题,例如“2GB 限制” - 请在此处查看问题和答案:stackoverflow.com/questions/1087982/…
  • "所以现在我需要创建一个大小为 3 GB 的新数组。现在我使用了 5 GB 的内存。"为什么不直接流式传输数据?
  • 因为流非常慢:(

标签: c# arrays


【解决方案1】:

如果您的过滤器可以就地工作,只需在开始时多分配 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;
}

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

【讨论】:

  • 谢谢,但它不能在开始时分配更多的东西,因为结果样本取决于用户操作。
【解决方案2】:

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

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

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

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

【讨论】:

    猜你喜欢
    • 2011-11-10
    • 2011-11-10
    • 2013-12-27
    • 2017-08-24
    • 1970-01-01
    • 2021-10-01
    • 2014-01-22
    相关资源
    最近更新 更多