内存分配责任

Memory allocation responsibility

本文关键字:责任 分配 内存      更新时间:2023-10-16

我一直在思考这个问题,但还没有找到任何解释。

哪个模块决定应该为C++程序分配多少内存?是操作系统决定编译器的建议吗?连接?

分配的内存中堆栈和堆的比率是多少?

对于不同的操作系统,答案是不同的。通常,可执行文件包含主线程所需的堆栈大小,由链接器放置在那里,它可能作系统设置覆盖。可以通过一种或多种方式配置操作系统设置,可能是按用户配置的。某些操作系统不需要预先指定堆栈大小,它们可以在使用堆栈时添加堆栈,或多或少是无限期的(直到达到硬限制或系统耗尽可用内存)。那些确实需要预先调整大小的人最初可能只分配地址空间而不是内存,并在堆栈达到该远时将地址映射到内存。

堆通常不会预先分配,因此没有"堆栈和堆的比率"。分配给进程的总内存可能会也可能不会受到限制 - 如果没有,那么它可以在系统资源允许的范围内增加,或者在 32 位系统上可能会受到可用地址空间的限制。

这不是

C++标准中的那种问题。 它依赖于编译器和操作系统。

有关链接器生成的类型示例,操作系统在确定程序请求的资源时需要考虑该类型,请参阅:

http://en.wikipedia.org/wiki/Executable_and_Linkable_Format#ELF_file_layout

在某些情况下,有一些 API 专门用于从操作系统请求资源:

在使用 GNU 编译器编译期间更改 Linux 中C++应用程序的堆栈大小

还有一些方法可以告诉操作系统在某些环境中设置配额和限制:

https://stackoverflow.com/questions/4983120/limit-memory-usage-for-a-single-linux-process

设置 Windows 进程(或用户)内存限制

如果您想对某个操作系统如何管理资源使用情况进行实证研究,您可能会使用进程监视器实用程序更好地了解它,而不是寻找文档......尤其是使用闭源操作系统。

取决于您的程序和操作系统。 通常,在启动时,只分配足够的内存来保存可执行文件,任何只读数据,并且通常大约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;
}

至少对于 32 位窗口,每个进程都有自己的地址空间副本,2G 用户 2G 内核(由所有进程共享),虚拟内存子系统确保访问相同位置的进程为其进程获取适当的数据。这就是程序可以具有相同的入口点并多次运行,同时不踩踏具有相同可执行文件的其他进程正在使用的数据的方式。

应用程序将继续使用更多的虚拟内存,内核将为该进程分配更多的物理内存,直到物理内存耗尽,交换空间/分页文件。您可以通过系统调用限制进程可以使用的内存。

堆栈

和堆几乎总是在可用内存的两端分配,因此堆栈从可用内存的顶部向下增长,而堆从底部增长(此决定取决于体系结构)。这允许它们单独增长,以便需要大量堆但不多堆栈的程序可以使用与需要大量堆栈但不太多堆的程序相同的计划。