StringBuilder 更改容量时出现异常!
这是我的代码行:
StringBuilder myCompleteMessage = new StringBuilder();
myCompleteMessage.Capacity = Int32.MaxValue-1;
也尝试过:
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)
here is my code line:
StringBuilder myCompleteMessage = new StringBuilder();
myCompleteMessage.Capacity = Int32.MaxValue-1;
tryed that also:
myCompleteMessage.Capacity = myCompleteMessage.MaxCapacity-1;
I get exception on line 2.
Exception of type 'System.OutOfMemoryException' was thrown.
Stack Trace:
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)
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
假设您使用的是 32 位系统,第二行将始终失败。您要求 .NET 为 StringBuilder 分配 4 GB 空间,这比进程需要使用的内存还要多(感谢 Joel 指出 char 占用 2 个字节,而不是 1 个字节)。
编辑
如果您使用 ILSpy 查看
StringBuilder
,您会在Capacity
集合中看到这段代码:通过将 Capacity 设置为 int.MaxValue - 1,您可以得知.NET 尝试分配 4 GB 字符数组,这就是代码失败的原因。
Assuming you are on a 32bit system, that second line will always fail. You're asking .NET to allocate 4 GB of space to your StringBuilder, which is more memory than the process has to work with (thanks to Joel for pointing out char takes up 2 bytes, not 1).
EDIT
If you take a look at
StringBuilder
with ILSpy, you see this bit of code in the set forCapacity
:By setting Capacity to int.MaxValue - 1, you're telling .NET to try and allocate a 4 GB char array, which is why the code is failing.
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)。
CLR heap is limited to 2GB objects ( http://blogs.msdn.com/b/joshwil/archive/2005/08/10/450202.aspx - for 2.0, I believe it the same for 4.0) so there is nothing that can allocate one continious block of memory above that size. For characters it gives you about Int.MaxValue/2 entries.
If you really need to manage such amount of text check out alternative implementations of MemoryStream that allow chunking or arrays that allow chuncking. If you want to stay within default classes - consider writing data to temporary file (temporary file created with DeleteOnClose may not be even commited to disk - so you get better performance compared to StringBuilder or MemoryStream that have to copy data on each increase in capacity - 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,则填充速度可能比 .NET 通过垃圾回收清理分配的内存的速度快,这就是它可能在 2048 个字符长度处停止的原因。此外,它在内部需要一个连续的内存块,这也可能会遇到问题。
不过,您的问题是关于“容量”属性的,您永远无法在 32 位系统上分配那么多容量。我发现了一个有趣的讨论 在 MSDN 上处理这个特定问题,通过测试发现实际容量要低很多,因为 Int32.MaxValue 容量转换为当所有字符均为 2 字节时,需要 4 GB 存储空间。
您可以改用内存映射文件吗? StringBuilder 不适合这个,您需要重新考虑您的设计。
StringBuilder's Capacity property is the number of characters to set aside as the string buffer. With UTF-8, a character can be up to 4 bytes. Even at 2 bytes, a capacity of
Int32.MaxValue - 1
is well over capacity for a 32-bit system, weighing in at 4 GB for just 2-byte characters (UTF-8/ASCII). Also, StringBuilder's default Capacity is already set to Int32.MaxValue if you look at the documentation.If you are looping to fill the StringBuilder, you may be filling it faster than .NET can clean up allocated memory through garbage collection, which is why it may be stopping at the 2048 character length. Also, internally it needs a contiguous block of memory, which it also may be running into an issue with.
Your question, though, is about the Capacity property, and you'll never be able to allocate that much capacity on a 32-bit system. I found an interesting discussion on MSDN dealing with this specific problem and through testing it was found that actual capacity is a great deal lower since Int32.MaxValue capacity translates to 4 GB of storage necessary when all characters are 2-bytes.
Can you use a Memory-Mapped file instead? StringBuilder's were not meant for this and you need to reconsider your design.