您正在寻找做出这一选择的人。David Cutler和他的团队选择1兆字节作为默认堆栈大小。与.NET或C#无关,当他们创建Windows NT时就被钉住了。当程序的EXE标头或CreateThread()winapi调用未明确指定堆栈大小时,它将选择一个兆字节。这是正常的方式,几乎所有程序员都将其留给操作系统来选择大小。
这种选择可能早于Windows NT设计,对此,历史太模糊了。如果卡特勒会写一本关于它的书,那会很好,但他从来不是作家。他对计算机的工作方式产生了极大的影响。他的第一个OS设计是RSX-11M,这是一种用于DEC计算机(数字设备公司)的16位操作系统。它极大地影响了Gary Kildall的CP / M,这是第一个用于8位微处理器的体面操作系统。这对MS-DOS影响很大。
他的下一个设计是VMS,该操作系统是具有虚拟内存支持的32位处理器的操作系统。非常成功。在公司开始瓦解时,DEC取消了他的下一个产品,无法与廉价的PC硬件竞争。提示微软,他们向他提出了他无法拒绝的提议。他的许多同事也加入了。他们在VMS v2(即Windows NT)上工作。DEC对此不高兴,钱转手解决了。我不知道VMS是否已经选择了1兆字节,我只非常了解RSX-11。这不太可能。
足够的历史。一兆字节是很多,一个真正的线程很少消耗超过几千字节的内存。因此,兆字节实际上是相当浪费的。但是,在按需分页的虚拟内存操作系统上您可以承受这种浪费,兆字节只是虚拟内存。只是处理器的编号,每4096个字节一个。在实际寻址之前,您永远不会真正使用物理内存(机器中的RAM)。
在.NET程序中,这是多余的,因为最初选择1兆字节的大小来容纳本机程序。这往往会创建大型堆栈框架,并在堆栈上存储字符串和缓冲区(数组)。众所周知,缓冲区溢出是恶意软件的攻击媒介,它可以操纵程序处理数据。.NET程序的工作方式不行,字符串和数组在GC堆上分配,并检查索引。使用C#在堆栈上分配空间的唯一方法是使用不安全的stackalloc关键字。
.NET中堆栈的唯一重要用途是抖动。它使用线程堆栈将MSIL即时编译为机器代码。我从来没有看过或检查过它需要多少空间,它取决于代码的性质以及是否启用了优化器,但是大概需要几十千字节。否则,这就是该网站的名称,.NET程序中的堆栈溢出非常致命。没有足够的空间(少于3 KB)来仍然可靠地JIT任何试图捕获异常的代码。Kaboom到桌面是唯一的选择。
最后但并非最不重要的一点是,.NET程序在堆栈上的工作效率很低。CLR将提交线程的堆栈。这是一个昂贵的词,这意味着它不仅保留堆栈的大小,而且还确保在操作系统的页面文件中保留空间,以便在必要时始终可以换出堆栈。未能提交是致命错误,将无条件终止程序。只有在内存很少且完全运行太多进程的RAM上才发生这种情况,在程序开始死亡之前,这种机器将变成糖蜜。15年前而不是今天可能出现的问题。将其程序调整为类似于F1赛车的程序的程序员使用<disableCommitThreadStack>
其.config文件中的元素。
Fwiw,Cutler并没有停止设计操作系统。那张照片是他在Azure上工作时拍摄的。
更新,我注意到.NET不再提交堆栈。不确定何时或为什么发生这种情况,自从我检查以来已经过了很长时间。我猜这种设计更改发生在.NET 4.5周围的某个地方。非常明智的变化。
Thread
构造函数的正确重载来指定堆栈大小。但是,这引出了一个问题,为什么您需要更大的堆栈?