即使内存可用,堆栈也较小的理由是什么?
最近,我在接受采访时被问到,当可用内存没有限制时,为什么要使用更小的堆栈?即使您拥有 4GB 物理内存,为什么还要将其设置在 1KB 范围内?这是标准设计实践吗?
Recently, I was asked in an interview, why would you have a smaller stack when the available memory has no limit? Why would you have it in 1KB range even when you might have 4GB physical memory? Is this a standard design practice?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(7)
其他答案都很好;我只是想指出这个问题中固有的一个重要误解。 你有多少物理内存完全无关。拥有更多的物理内存只是一种优化;它避免了必须使用磁盘作为存储。堆栈消耗的宝贵资源是地址空间,而不是物理内存。目前未使用的堆栈位甚至不会驻留在物理内存中;它们将被分页到磁盘。但一旦提交,它们就会消耗虚拟地址空间。
The other answers are good; I just thought I'd point out an important misunderstanding inherent in the question. How much physical memory you have is completely irrelevant. Having more physical memory is just an optimization; it prevents having to use disk as storage. The precious resource consumed by a stack is address space, not physical memory. The bits of the stack that aren't being used right now are not even going to reside in physical memory; they'll be paged out to disk. But as soon as they are committed, they are consuming virtual address space.
你的筹码越小,你可以拥有的筹码就越多。 1kB 的堆栈毫无用处,因为我无法想象一个具有这么小的页面的架构。更典型的大小是 128kB-1MB。
由于每个线程都有自己的堆栈,因此您可以拥有的堆栈数量是您可以拥有的线程数量的上限。有些人抱怨他们无法在 32 位 Windows 进程的标准 2GB 地址空间中创建超过 2000 个线程,因此有些人想要更小的堆栈来允许更多的线程也就不足为奇了。
另外,请考虑,如果必须提前完全保留堆栈,则它会从地址空间中切出一块,直到堆栈不再使用(即线程退出)为止,该块无法返回。然后,这块保留的地址空间限制了您可以进行的连续分配的大小。
The smaller your stacks, the more of them you can have. A 1kB stack is pretty useless, as I can't think of an architecture that has pages that small. A more typical size is 128kB-1MB.
Since each thread has its own stack, the number of stacks you can have is an upper limit on the number of threads you can have. Some people complain about the fact that they can't create more than 2000 threads in a standard 2GB address space of a 32-bit Windows process, so it's not surprising that some people would want even smaller stacks to allow even more threads.
Also, consider that if a stack has to be completely reserved ahead of time, it is carving a chunk out of your address space that can't be returned until the stack isn't used anymore (i.e. the thread exits). That chunk of reserved address space then limits the size of a contiguous allocation you can make.
我不知道“真正的”答案,但我的猜测是:
它是按需提交的。
你真的需要它吗?
如果系统使用 1 MiB 作为堆栈,那么具有 1024 个线程的典型系统将使用 1 GiB 内存(大部分情况下)什么都不做……这可能不是您想要的,特别是因为您并不真正需要它。
I don't know the "real" answer, but my guess is:
It's committed on-demand.
Do you really need it?
If the system uses 1 MiB for a stack, then a typical system with 1024 threads would be using 1 GiB of memory for (mostly) nothing... which may not be what you want, especially since you don't really need it.
原因之一是,尽管现在内存很大,但它仍然不是无限的。 32 位进程通常限制为 4GB 地址空间(是的,您可以使用 PAE 来增加该地址空间,但这需要操作系统的支持并返回分段内存模型。)每个线程都会使用部分内存它的堆栈,如果堆栈大小为兆字节(无论是否分页),它都会占用应用程序地址空间的很大一部分。
堆栈越小,您可以挤入应用程序的线程就越多,并且可用于其他所有操作的内存也就越多。理想情况下,您希望堆栈足够大以处理通过线程的所有可能的控制流,但又足够小以免浪费地址空间。
One reason is, even though memory is huge these days, it is still not unlimited. A 32-bit process is normally limited to 4GB of address space (yes, you can use PAE to increase that, but that requires support from the OS and a return to a segmented memory model.) Each thread uses up some of that memory for its stack, and if a stack is megabytes in size -- whether it's paged in or not -- it's taking up a significant part of the app's address space.
The smaller the stack, the more threads you can squeeze into the app, and the more memory you have available for everything else. Ideally, you want a stack just large enough to handle all possible control flows through the thread, but small enough that you don't have wasted address space.
这里有两件事。首先,堆栈大小的限制将限制系统中进程/线程的数量。而且,限制不是因为物理内存的大小,而是因为可寻址虚拟内存的限制。其次,很少有进程/线程需要更多的堆栈大小,如果需要,他们可以要求它(库无缝地处理这个)。因此,当启动一个新的进程/线程时,给它们一个小的堆栈空间是有意义的。
There are two things here. First, the limit on the stack size will put the limit on number of processes/threads in the system. And then too, the limit is not because of the size of physical memory but because of the limit on addressable virtual memory. Secondly, rarely processes/threads need more stack size then that, and if they do, they can ask for it (libraries handle this seamlessly). So, when starting a new process/thread, it makes sense to give them a small stack space.
这里的其他答案已经提到了核心概念,即堆栈消耗的最重要的资源是地址空间(因为它的实现需要连续的地址空间块),并且每个线程在窗口上消耗的默认空间并不是微不足道的。
然而,整个故事在许多层面和层面上都非常微妙(并且可以并且将会随着时间的推移而改变)。
Mark Russinovich 撰写的这篇文章是他的“突破 Windows 极限”系列的一部分,该文章位于 极其详细的分析级别。不过,这篇文章绝不是一篇介绍性文章,而且大多数人不会认为它是在工作面试中需要了解的内容,除非您正在面试该特定领域的工作。
Other answers here already mention the core concept, that the most significant consumed resource of a stack is address space (since its implementation requires chunks of contiguous address space) and that the default space consumed on windows for each thread is not insignificant.
However the full story is extremely nuanced (and can and will change over time) over many layers and levels.
This article by Mark Russinovich as part of his "Pushing the limits of Windows" series goes into extremely detailed levels of analysis. The work is in no way an introductory article though, and most people would not consider it the sort of thing that would be expected to be known in a job interview unless perhaps you were interviewing for a job in that particular field.
也许是因为每次调用一个函数时,操作系统都必须分配内存作为该函数的堆栈。由于函数可以链接,因此多个函数调用将导致更多的堆栈分配。较大的默认堆栈大小(例如 4GiB)是不切实际的。但这只是我的猜测......
Maybe because everytime you call a function the OS has to allocate memory to be the stack of that function. Because functions can chain, several function calls will incur more stack allocations. A large default stack size, like 4GiB, would be impractical. But that's just my guess...