内存释放字符串生成器和c#中的d字节[]:内存不足异常

时间:2009-11-14 08:17:37

标签: c#

我正在研究c#。我想知道如何释放stringbuilder n byte [] ....因为我在使用字符串生成器时遇到内存不足异常....     另一件事是String.Replace()也给出了一个内存不足的例外,否则还有其他方法可以做同样的事情....请告诉我如何克服这些问题......    提前谢谢

4 个答案:

答案 0 :(得分:5)

如果您正在获取OOM,那么您需要保留太多数据。听起来我应该使用TextWriter(替换StringBuilder)或BinaryWriter / Stream(替换byte[]) - 特别是{ {1}}和StreamWriter(写入文件)。

例如:

FileStream

像这样的基于流的API的优点是,一旦你编写了一个数据块,它就可以被垃圾收集等。

答案 1 :(得分:4)

你建造的弦有多大?你知道它会有多大吗?如果是这样,设置StringBuilder的容量。

如果你不这样做,它会从容量16开始,然后每次突破该限制时加倍。容量将为16,32,64,128。

每次执行此操作时,可能需要重新分配内存。

如果数据那么大,那么在文件流而不是StringBuilder中构建数据会更好吗?

答案 2 :(得分:3)

以下是一些可以试验的代码:

using System;
using System.Text;

class Program {
  static void Main(string[] args) {
    StringBuilder sb = new StringBuilder();
    try {
      //sb.Capacity = 690 * 1024 * 1024;
      while (true) sb.Append("asdf");
    }
    catch (OutOfMemoryException) {
      Console.WriteLine("Died at: {0:N0} characters", sb.Capacity);
      Console.WriteLine("Memory used: {0:N0} bytes", GC.GetTotalMemory(false));
      Console.ReadLine();
    }
  }
}

我的机器上的输出(Win7 32位):

Died at: 268,435,456 characters 
Memory used: 537,091,632 bytes

32位操作系统提供了一个具有接近2千兆字节虚拟内存的进程。正如您所看到的,示例程序很好地消失了,只消耗了25%。问题是虚拟内存地址空间碎片。可用的2千兆字节需要存储代码和数据。您可以通过SysInternal的VMMap utility来了解虚拟机是如何被分割出来的。

您可以通过对StringBuilder工作方式的一些了解来解决这个问题。它使用内部数组来存储字符串。根据需要重新分配此数组以存储增长的字符串,每次将大小加倍。 Capacity属性告诉您该数组的大小。

这会导致另一种碎片,堆碎片。在数组大小加倍之后,可以收集旧数组,但会生成一个“空闲块”,该块不能合并回来以便可用于大型连续分配。这是大对象堆和Windows堆管理器的实现细节,谷歌“后备缓存”以了解更多信息。

一种解决方法是在虚拟内存空间崩溃之前快速吞噬虚拟内存空间。工作中删除评论以查看此信息。在我的机器上:

Died at: 723,517,440 characters
Memory used: 1,447,256,944 bytes

我通过实验微调了容量值,您可能必须这样做以使其在您的机器上运行。差异非常大,差不多是原来的3倍。请注意,这不太可能在真实程序中很好地再现,时间是至关重要的。或者在另一台机器上,确保远低于截止点。实际上,一旦你使用的缓冲区超过1.34亿个字符,你就会冒OOM的风险。

答案 3 :(得分:0)

StringBuilder对象的最大容量可以为Int32.MaxValue-MaxCapacity:2,147,483,647个字符。 如果通过调用没有MaxCapacity参数的StringBuilder类构造函数之一来实例化StringBuilder对象,则此对象将使用默认的最大容量Int32.MaxValue。 如果使用StringBuilder对象实例化,则定义MaxCapasity值的构造函数,例如

int capacity = 520;
int maxCapacity = 2048;
StringBuilder stringBuilder = new StringBuilder(capacity, maxCapacity);

,并且如果此实例化的stringBuilder中的字符数将超过2048,则StringBuilder对象不会分配额外的内存,而是会引发StackOverflow异常。因此,如果实例化的StringBuilder对象中的字符数量将超过默认值或在构造函数中设置的最大容量,则将引发错误。 有关它的更多信息:Instantiating a StringBuilder object

可以通过添加以下代码来解决此问题:在将字符添加到StringBuilder对象之前,检查此操作之后执行的操作将不超过最大容量,如果可以,则代码可以创建一个新的StringBuilder对象,并且将这些字符添加到其中。将所有必需的字符添加到一个或多个StringBuilder对象之后,此附加代码会将这些StringBuilder对象中的数据组合到所需的报告中。