Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/259.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
为什么以C#为单位的堆栈大小正好是1MB?_C#_Stack_Clr_Stack Size - Fatal编程技术网

为什么以C#为单位的堆栈大小正好是1MB?

为什么以C#为单位的堆栈大小正好是1MB?,c#,stack,clr,stack-size,C#,Stack,Clr,Stack Size,今天的PC有大量的物理RAM,但C#的堆栈大小对于32位进程只有1MB,对于64位进程只有4MB() 为什么CLR中的堆栈大小仍然如此有限 为什么它正好是1MB(4MB)(而不是2MB或512KB)?为什么决定使用这些数量 我对该决定背后的考虑因素和原因感兴趣默认保留堆栈大小由链接器指定,开发人员可以通过在链接时更改PE值来覆盖它,或者通过为CreateThread指定dwStackSize参数来覆盖单个线程WinAPI函数 如果创建的线程的初始堆栈大小大于或等于默认堆栈大小,则将其四舍五入到最

今天的PC有大量的物理RAM,但C#的堆栈大小对于32位进程只有1MB,对于64位进程只有4MB()

为什么CLR中的堆栈大小仍然如此有限

为什么它正好是1MB(4MB)(而不是2MB或512KB)?为什么决定使用这些数量


我对该决定背后的考虑因素和原因感兴趣

默认保留堆栈大小由链接器指定,开发人员可以通过在链接时更改PE值来覆盖它,或者通过为
CreateThread
指定
dwStackSize
参数来覆盖单个线程WinAPI函数

如果创建的线程的初始堆栈大小大于或等于默认堆栈大小,则将其四舍五入到最接近的1 MB倍数

为什么32位进程的值等于1MB,64位进程的值等于4MB?我认为你应该问问开发人员,谁设计了Windows,或者等到他们中有人回答你的问题

也许马克·鲁西诺维奇知道这一点,你也可以告诉他。也许你可以在他的WindowsInternals书籍中找到这些信息,早于第六版,第六版描述的堆栈信息比他的更少。或者雷蒙德·陈知道原因,因为他写了一些关于Windows内部结构及其历史的有趣的东西。他也可以回答你的问题,但你应该把建议张贴到网站上

但在这个时候,我将试图解释一些可能的原因,为什么微软使用MSDN、Mark和Raymond的博客选择这些值

默认值有这些值,可能是因为早期PC速度较慢,在堆栈上分配内存比在堆中分配内存快得多。由于堆栈分配要便宜得多,所以使用了它们,但它需要更大的堆栈大小

因此,该值是大多数应用程序的最佳保留堆栈大小。它是最优的,因为它允许进行大量嵌套调用,并在堆栈上分配内存,以便将结构传递给调用函数。同时,它允许创建大量线程

现在,这些值主要用于向后兼容,因为作为参数传递给WinAPI函数的结构仍然在堆栈上分配。但是,如果不使用堆栈分配,那么线程的堆栈使用量将大大低于默认的1MB,这是一种浪费,正如Hans Passant所提到的。为了防止这种情况,如果在应用程序的PE头中没有指定其他页,则操作系统只提交堆栈的第一页(4KB)。其他页面按需分配

一些应用程序覆盖保留的地址空间,并最初致力于优化内存使用。例如,IIS本机进程线程的最大堆栈大小为256 KB()。默认值的减少是由Microsoft完成的:

最好选择尽可能小的堆栈大小,并提交线程或光纤可靠运行所需的堆栈。为堆栈保留的每个页面都不能用于任何其他目的

资料来源:

  • 你看到的是做出这个选择的那个人。David Cutler和他的团队选择1兆字节作为默认堆栈大小。与.NET或C#无关,这一点在他们创建Windows NT时已经确定。当程序的EXE头或CreateThread()winapi调用未显式指定堆栈大小时,它会选择1兆字节。这是正常的方式,几乎任何程序员都会让操作系统来选择大小

    这个选择可能早于WindowsNT的设计,历史对此太模糊了。如果卡特勒能就此写一本书就好了,但他从来都不是作家。他对计算机的工作方式有着非凡的影响力。他的第一个操作系统设计是RSX-11M,是DEC计算机(数字设备公司)的16位操作系统。它严重影响了Gary Kildall的CP/M,这是第一个适合8位微处理器的操作系统。这严重影响了MS-DOS

    他的下一个设计是VMS,一个支持虚拟内存的32位处理器操作系统。非常成功。他的下一个计划在12月公司开始解体时被取消,无法与廉价的PC硬件竞争。在微软的暗示下,他们向他提出了一个他无法拒绝的提议。他的许多同事也加入了。他们在VMS v2上工作,更广为人知的是Windows NT。DEC对此感到不安,钱转手解决了这件事。我不知道虚拟机是否已经选择了1兆字节,我只知道RSX-11足够好。这并非不可能

    足够的历史。一兆字节是一批,一个真正的线程很少消耗超过两把千字节。所以一兆字节实际上是相当浪费的。然而,在按需分页的虚拟内存操作系统上,兆字节只是虚拟内存,这是一种您可以承受的浪费。只需向处理器发送数字,每4096字节一个。你永远不会真正使用物理内存,机器中的RAM,直到你真正寻址它

    在.NET程序中,它是多余的,因为最初选择1兆字节的大小是为了容纳本机程序。它倾向于创建大型堆栈帧,并在堆栈上存储字符串和缓冲区(数组)。由于恶意软件攻击向量臭名昭著,缓冲区溢出可以用数据操纵程序。不是.NET程序的工作方式,在GC堆上分配字符串和数组,并检查索引。使用C#在堆栈上分配空间的唯一方法是使用不安全的stackalloc关键字

    NET中堆栈的唯一非平凡用法是抖动。它使用线程堆栈将MSIL及时编译为机器代码。我从未见过或检查过它需要多少空间,这取决于代码的性质以及optim是否