您正在查看做出该选择的人。 David Cutler和他的团队将一兆字节选为默认堆栈大小。这与.NET或C#无关,而是在创建Windows NT时确定的。当程序的EXE头文件或CreateThread()winapi调用未明确指定堆栈大小时,它会选择1MB。这是正常方式,几乎所有程序员都会让操作系统选择大小。
这个选择可能早于Windows NT设计,历史太过混沌。如果Cutler能够写一本关于它的书就好了,但他从来没有成为一名作家。他对计算机工作方式的影响非常大。他的第一个操作系统设计是RSX-11M,这是DEC计算机(Digital Equipment Corporation)的16位操作系统。它对Gary Kildall的CP / M产生了很大影响,这是第一个适用于8位微处理器的良好操作系统。这严重影响了MS-DOS。
His next design was VMS, an operating system for 32-bit processors with virtual memory support. It was very successful. His next project was cancelled by DEC around the time the company started disintegrating, as they were unable to compete with cheap PC hardware. Microsoft made him an offer he could not refuse, and many of his co-workers joined too. They worked on VMS v2, better known as Windows NT. DEC was upset about it and money changed hands to settle it. Whether VMS had already reached one megabyte is something I don't know, but I am familiar enough with RSX-11. This is enough history. One megabyte is a lot, as a real thread rarely consumes more than a couple of kilobytes. So a megabyte is actually quite wasteful. However, it is the kind of waste that can be afforded on a demand-paged virtual memory operating system, as that megabyte is just virtual memory - just numbers to the processor, one for every 4096 bytes. Physical memory, or the RAM in the machine, is never actually used until it is addressed.
它在.NET程序中显得特别过度,因为最初选择了1MB大小以适应本地程序。这些程序往往会在栈上创建大型堆栈帧,将字符串和缓冲区(数组)存储在栈上。由于成为恶意软件攻击向量而臭名昭著,缓冲区溢出可以操纵数据的程序。.NET程序的工作方式与此不同,字符串和数组分配在GC堆上并进行索引检查。使用C#在堆栈上分配空间的唯一方法是使用不安全的
stackalloc关键字。
.NET中栈的唯一非平凡用法是Jitter。它使用您的线程的堆栈将MSIL即时编译为机器代码。我从未见过或检查过它需要多少空间,这取决于代码的性质以及是否启用了优化器,但大约需要几十KB。否则,这就是此网站如何得到其名称的原因,.NET程序中的堆栈溢出非常致命。剩余空间不足(小于3KB)以仍然可靠地JIT尝试捕获异常的任何代码。桌面上的Kaboom是唯一的选择。
最后但并非最不重要的,一个.NET程序在堆栈方面做了一些相当低效的事情。CLR会
提交一个线程的堆栈。这是一个昂贵的词,意思是它不仅保留了堆栈的大小,还确保在操作系统的分页文件中保留了空间,以便在必要时可以始终交换出堆栈。未能提交是致命错误,并无条件地终止程序。这只会发生在内存很少的机器上运行过多进程的情况下,这样的机器在程序开始死亡之前就会变得像糖浆一样。15年前可能存在的问题,但今天已不再是问题。将他们的程序调整为像F1赛车一样运行的程序员,在其.config文件中使用
<disableCommitThreadStack>
元素。
顺便说一句,卡特尔并没有停止设计操作系统。那张照片是在他工作于Azure期间拍的。
更新,我注意到.NET不再提交堆栈。不确定何时或为什么发生了这种情况,因为我很久没有检查了。我猜测这种设计变更大约发生在.NET 4.5左右。这是一个相当明智的变化。
1572864
字节的默认堆栈大小(使用GetCurrentThreadStackLimits Win32 API检索)。我能够使用stackalloc
大约1500000
字节而不会出现StackOverflowException。 - Giorgi Chakhidze