StringBuilder的MaxCapacity

Bac*_*ave 2 c# stringbuilder

为什么这段代码会在i = 690864192上抛出OutOfMemoryException?

StringBuilder sb = new StringBuilder();
                for (int i = 0; i < Int32.MaxValue; i++)
                {
                    sb.Append("s");
                }
                Console.WriteLine(sb.ToString());
                Console.Read();
Run Code Online (Sandbox Code Playgroud)

默认容量是16个字符,但是这需要增加到最大值,即int.MaxValue = 2,147,483,647.那么为什么当chars的数量是690,864,192而远远低于最大容量时,它会抛出异常?

Eri*_*ert 28

所以基本上我没有足够的RAM来存储具有那么多字符的StringBuilder实例?

不不不不不.

RAM无关紧要; RAM近二十年来一直没有相关的记忆测量方法!虚拟地址空间是相关的衡量标准.

令人惊讶的是,相信内存仍然像20世纪80年代在DOS机器中那样工作的人数.我的建议是了解现代操作系统如何处理内存.RAM是一种性能优化.内存是页面文件.

这样想吧.你有一个停车场(页面文件)可以容纳一百万辆汽车(内存页).你有一个可以容纳十辆车的车道(RAM).你有一个可以容纳一千个密钥(虚拟内存)的密钥环.你拥有一千辆汽车.您经常使用的十个是在车道上.另外990在街道的停车场.

当您在车道上用完房间时,您只需将其中一辆车移至停车场.(RAM可以快速访问常用页面.)

但是当你购买汽车#1001时,你用完的资源就是钥匙圈上的空间,而不是停车场车道上的房间.您可以随时在车道上腾出更多空间,而且您在停车场有额外的空间,但您的钥匙圈只是如此之大.

为什么当字符数为690,864,192且远小于最大容量时,是否会引发异常?

在32位Windows计算机上,每个进程只能获得2 GB的用户可寻址虚拟地址空间.

每个字符两个字节,6.9亿个字符是14亿字节,这是2GB地址空间的很大一部分.你只剩下大约.6 GB来适应这个过程中的其他一切.在某些时候,字符串构建器将需要分配另一个块,并且在您的地址空间中的任何位置都没有该大小的空闲块,因此分配失败.

你为什么要首先尝试这样做?一个14亿字节的字符串是完全荒谬的.

  • 我只是无聊,想尝试一下。我在继承方面做了类似的事情。 (3认同)
  • @DavidKlempfner 这是一个很棒的理由:) (2认同)

Sim*_*ead 6

每次StringBuilder分配一个新的char[](通过指向前一个chunk实例......这是另一个StringBuilder......你给垃圾收集器施加了巨大的压力。

对象的大小有内存限制。在到达结束之前,您的对象可能会最大限度地为您的应用程序进程分配内存......因此OutOfMemoryException在任何一种情况下。

StringBuilder您拥有的最后一个实例指向它最大化之前的最后一个实例......那个也指向它最大化之前的前一个实例......等等。你有一个巨大的 GC 根图,永远不会被清理。