CLR 强制执行的 1 MB 堆栈大小限制是针对线程还是整个应用程序/进程?

Posted

技术标签:

【中文标题】CLR 强制执行的 1 MB 堆栈大小限制是针对线程还是整个应用程序/进程?【英文标题】:1 MB stack size limit enforced by the CLR is for a thread or the entire application/process? 【发布时间】:2017-06-22 22:16:26 【问题描述】:

阅读this 和this 的帖子后,我运行了一个非常简单的C# 程序,如下所示:

static void Main(string[] args)

    Thread t = new Thread(new ThreadStart(myFunc), 2097152);
    t.start();

Thread 类的构造函数的第二个参数是要为线程分配的堆栈大小(以字节为单位)。数字 2097152 相当于 2 兆字节。但是我的程序仍然可以正常工作吗?如果我的程序在为此线程分配堆栈空间(完整应用程序本身的限制为 1 MB)时不会抛出错误,或者我错过了一些非常明显的东西。最初我认为这可能是编译器检查本身。

CLR 如何确保线程的堆栈分配大小不会超出界限?

附: : 我的应用是 32 位控制台应用

【问题讨论】:

您在说什么“1 MB 堆栈大小限制”?线程的默认堆栈大小为 1MB,但这不是硬性限制。您传递的参数实际上是修改此默认值的方法。请更具体地说明您的要求。 你从哪里得到堆栈只能是 1MB 的想法?既然您正在创建一个 2MB 的堆栈,那么您认为堆栈只能是 1MB 的想法显然是错误的,那么您为什么会相信呢? 这是我今天在 Windows 中第一次介绍此限制。事实上,现在我意识到这不是限制,而是可以在每个线程的基础上修改的配置。this 论坛上的第一行让我进入了不同的方向 - The default stack size for a .NET application is 1 MB (default is 256 KB for 32-bit ASP.NET apps and 512 KB for 64-bit ASP.NET apps)。我提到的任何一个帖子都没有完全使用过per-thread这个词。对于初学者来说,理解起来可能不是那么简单。 谢谢;理解为什么人们相信关于编程语言的错误信息对我很有帮助。那么,你相信程序中的每个线程都从 1MB 的堆栈缓冲区中挖出自己的空间吗?那么如果有 1000 个线程,它们每个会得到 1K? 谢谢,这很有帮助。是的,现在你明白为什么线程非常昂贵了。一千个线程将每个保留一百万字节的地址空间。这就是为什么你永远不会制作一千个线程。您为每个 CPU 创建一个线程并将它们池化。一个线程在您使用时从池中出来,完成后又回到池中,并且您创建的线程不会超过处理它们的 CPU。 【参考方案1】:

1MB 只是每个线程的默认堆栈大小,不适用于整个应用程序。每个线程都有自己的堆栈。当您在线程构造函数中指定不同的堆栈大小时,您将覆盖该线程的默认值。

如果你想测试堆栈大小的限制,你需要调用一个递归函数,直到堆栈被填满并溢出(因此这个网站的名字)。简单地创建更多线程只会创建更多堆栈。

【讨论】:

现在我明白了。它根本不是一个限制,而是一个与线程相关的可配置值,而是可以修改的。如果我们在创建线程期间未指定任何内容,则 1 MB 是 Windows 假定的默认配置。一旦我们设置了这个值,那么它就会变成一个限制,如果由于存储本地方法变量(存储在堆栈上)或用于维护方法调用的堆栈帧而超过它,则会引发*** 异常。现在我得到了一个更好的画面,堆栈内存与线程而不是进程非常耦合。【参考方案2】:

As per Microsoft documentation,

“从 .NET Framework 4 开始,只有完全受信任的代码才能将 maxStackSize 设置为大于默认堆栈大小(1 兆字节)的值。如果在以部分信任运行代码时为 maxStackSize 指定更大的值, maxStackSize 被忽略并使用默认堆栈大小。不抛出异常。任何信任级别的代码都可以将 maxStackSize 设置为小于默认堆栈大小的值。"

【讨论】:

非常好的信息。很高兴知道这些关于 partil-trust 代码限制 w.r.t 的内部细节。最大堆栈大小。

以上是关于CLR 强制执行的 1 MB 堆栈大小限制是针对线程还是整个应用程序/进程?的主要内容,如果未能解决你的问题,请参考以下文章

在 .NET 中的 CLR 上下文中,堆栈空间是如何分配的

是啥限制了我在内存方面对堆栈的使用?

CloudKit 的 CKasset 文件大小限制

为啥堆栈内存大小如此有限?

在 CLR 4.0 中,单个对象的大小仍限制为 2 GB?

应用程序执行期间跟踪堆栈大小