更改容量时出现StringBuilder异常
本文关键字:StringBuilder 异常 容量 | 更新日期: 2023-09-27 18:01:36
下面是我的代码行:
StringBuilder myCompleteMessage = new StringBuilder();
myCompleteMessage.Capacity = Int32.MaxValue-1;
try that also:
myCompleteMessage.Capacity = myCompleteMessage.MaxCapacity-1;
第2行出现异常
Exception of type 'System.OutOfMemoryException' was thrown.
堆栈跟踪:
at System.String.GetStringForStringBuilder(String value, Int32 startIndex, Int32 length, Int32 capacity)
at System.Text.StringBuilder.set_Capacity(Int32 value)
at Orca.Server.HandleClientComm(Object newClient) in C:'Users'Dan'Documents'Visual Studio 2010'Projects'msig'Orca'Server.cs:line 100
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Threading.ThreadHelper.ThreadStart(Object obj)
假设您使用的是32位系统,那么第二行代码总是会失败。你要求。net为StringBuilder分配4 GB的空间,这比进程必须使用的内存要多(感谢Joel指出char占用2字节,而不是1)。
编辑
如果你用ILSpy看一下StringBuilder
,你会看到Capacity
集合中的这段代码:
if (this.Capacity != value)
{
int num = value - this.m_ChunkOffset;
char[] array = new char[num];
Array.Copy(this.m_ChunkChars, array, this.m_ChunkLength);
this.m_ChunkChars = array;
}
通过将Capacity设置为int。MaxValue - 1,你告诉。net尝试分配一个4gb的字符数组,这就是代码失败的原因。
CLR堆限制为2GB对象(http://blogs.msdn.com/b/joshwil/archive/2005/08/10/450202.aspx -对于2.0,我相信对于4.0也是如此),因此没有任何东西可以分配超过该大小的连续内存块。对于字符,它给你大约Int。MaxValue/2条目。
如果你真的需要管理这么多的文本,请查看允许分块的MemoryStream或允许分块的数组的替代实现。如果你想保持默认类-考虑将数据写入临时文件(用DeleteOnClose创建的临时文件甚至可能不会提交到磁盘-因此与每次增加容量都必须复制数据的StringBuilder或MemoryStream相比,您可以获得更好的性能- http://msdn.microsoft.com/en-us/library/system.io.fileoptions.aspx)。
StringBuilder的Capacity属性是要留出作为字符串缓冲区的字符数。使用UTF-8,一个字符最多可以有4个字节。即使是2字节,Int32.MaxValue - 1
的容量也远远超过32位系统的容量,仅2字节字符(UTF-8/ASCII)的容量为4 GB。此外,StringBuilder的默认容量已经设置为Int32。MaxValue
如果你正在循环填充StringBuilder,你可能会比。net通过垃圾收集清理分配的内存更快地填充它,这就是为什么它可能会在2048个字符长度时停止。此外,在内部,它需要一个连续的内存块,这也可能会遇到问题。
你的问题是关于Capacity属性的,你永远无法在32位系统上分配那么大的容量。我在MSDN上发现了一个有趣的讨论来处理这个特定的问题,通过测试发现,自Int32以来,实际容量要低得多。当所有字符都是2字节时,MaxValue容量转换为4gb所需的存储空间。
可以使用内存映射文件吗?StringBuilder不是为了这个目的,你需要重新考虑你的设计。