为什么这段代码会在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亿字节的字符串是完全荒谬的.
每次StringBuilder分配一个新的char[](通过指向前一个chunk实例......这是另一个StringBuilder......你给垃圾收集器施加了巨大的压力。
对象的大小有内存限制。在到达结束之前,您的对象可能会最大限度地为您的应用程序进程分配内存......因此OutOfMemoryException在任何一种情况下。
StringBuilder您拥有的最后一个实例指向它最大化之前的最后一个实例......那个也指向它最大化之前的前一个实例......等等。你有一个巨大的 GC 根图,永远不会被清理。