【发布时间】:2012-05-05 03:00:55
【问题描述】:
我一直在思考这个问题,但还没有找到任何解释。
哪个模块决定应该分配多少内存,比方说,一个 C++ 程序?是操作系统决定编译器的推荐吗? ..链接器?
而堆栈和堆在分配的内存中的比例是多少?
【问题讨论】:
标签: c++ memory-management operating-system
我一直在思考这个问题,但还没有找到任何解释。
哪个模块决定应该分配多少内存,比方说,一个 C++ 程序?是操作系统决定编译器的推荐吗? ..链接器?
而堆栈和堆在分配的内存中的比例是多少?
【问题讨论】:
标签: c++ memory-management operating-system
对于不同的操作系统,答案是不同的。通常,可执行文件包含主线程所需的堆栈大小,由链接器放置在那里,可能会被操作系统设置覆盖。操作系统设置可以通过一种或多种方式进行配置,可能针对每个用户。一些操作系统不需要预先指定堆栈大小,它们可以在使用堆栈时或多或少无限期地添加堆栈(直到达到硬限制或系统耗尽可用内存)。那些确实需要预先确定大小的人最初可能只分配地址空间而不是内存,并在堆栈达到那个距离时将地址映射到内存。
堆通常不会预先分配,因此没有“堆栈和堆的比例”。分配给进程的总内存可能会受到限制,也可能不会受到限制——如果没有,那么它可以达到系统资源允许的上限,或者在 32 位系统上可能会受到可用地址空间的限制。
【讨论】:
这不是 C++ 标准中的问题。它依赖于编译器和操作系统。
有关链接器产生的、操作系统在确定程序请求的资源时会考虑的类型的示例,请参阅:
http://en.wikipedia.org/wiki/Executable_and_Linkable_Format#ELF_file_layout
在某些情况下,有专门从操作系统请求资源的 API:
Change stack size for a C++ application in Linux during compilation with GNU compiler
还有一些方法可以告诉操作系统在某些环境中设置配额和限制:
https://stackoverflow.com/questions/4983120/limit-memory-usage-for-a-single-linux-process
Set Windows process (or user) memory limit
如果您想对某个操作系统如何管理资源使用进行实证研究,您可能会通过进程监视器实用程序来更好地了解它,而不是寻找文档......特别是。使用闭源操作系统。
【讨论】:
取决于您的程序和操作系统。通常,在启动时只分配足够的内存来保存可执行文件、任何只读数据,通常大约 4k 用于堆栈。然后,当您调用 malloc 或 new 来分配内存时,您将获得虚拟内存空间,而无需任何物理内存对其进行备份。这称为延迟分配,只有在您实际写入时才会物理分配内存。
编译并计时以下内容以了解我在说什么:
//justwrites.c
#include <stdlib.h>
int main(int argc, char **argv) {
int *big = calloc(sizeof(int),19531); // number of writes
return 0;
}
// deadbeef.c
#include <stdlib.h>
int main(int argc, char **argv) {
int *big = malloc(sizeof(int)*20000000); // allocate 8 million bytes
// immediately write to each page to simulate all at once allocation
// assuming 4k page size on 32bit machine
for ( int* end = big + 20000000; big < end; big+=1024 ) *big = 0xDEADBEEF ;
return 0;
}
// bigmalloc.c
#include <stdlib.h>
int main(int argc, char **argv) {
int *big = malloc(sizeof(int)*20000000); // allocate 80 million bytes
return 0;
}
【讨论】:
malloc 使用的相同底层方法(即 CreateFileMapping 没有文件句柄,也没有特殊选项),其他 Windows 编译器肯定可以通过这种方式实现 malloc。
至少对于 32 位 Windows,每个进程都有自己的地址空间副本,2G 用户 2G 内核(由所有进程共享),虚拟内存子系统确保访问相同位置的进程获得适当的数据他们的过程。这就是一个程序可以具有相同的入口点并多次运行而不踩踏具有相同可执行文件的其他进程正在使用的数据的方式。
应用程序将继续使用更多的虚拟内存,内核会为该进程分配更多的物理内存,直到物理内存、交换空间/分页文件用完为止。您可以通过系统调用限制进程可以使用的内存。
堆栈和堆几乎总是分配在可用内存的两端,因此堆栈从可用内存的顶部向下增长,而堆从底部向上增长(这个决定取决于架构)。这允许它们单独增长,以便需要大量堆但不需要太多堆的程序可以使用与需要大量堆但不需要太多堆的程序相同的计划。
【讨论】: