在c++中定义全局或静态数组时,它的内存不是在程序开始时立即保留的,而是只在我们向数组写入一次时才保留。我发现令人惊讶的是,如果我们只写到数组的一小部分,它仍然没有保留整个内存。考虑以下示例,它稀疏地写入全局数组:
#include <cstdio>
#include <cstdlib>
#define MAX_SIZE 250000000
double global[MAX_SIZE];
int main(int argc, char** argv) {
if(argc<2) {
printf("usage: %s <step size>\n", argv[0]);
exit(EXIT_FAILURE);
}
size_t step_size=atoi(argv[1]);
for(size_t i=0; i<MAX_SIZE; i+=step_size) {
global[i]=(double) i;
}
printf("finished\n"); getchar();
return EXIT_SUCCESS;
}现在,对不同的步长执行此操作,并查看top的输出,例如:
./a.out 1000000
./a.out 100000
./a.out 10000
./a.out 1000
./a.out 100
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
15718 user 20 0 1918m 1868 728 S 0 0.0 0:00.00 a.out
15748 user 20 0 1918m 10m 728 S 0 0.1 0:00.00 a.out
15749 user 20 0 1918m 98m 728 S 1 0.8 0:00.04 a.out
15750 user 20 0 1918m 977m 728 S 0 8.1 0:00.39 a.out
15751 user 20 0 1918m 1.9g 728 S 23 15.9 0:00.80 a.outRES列表示仅在小块中保留内存,这也意味着数组在物理内存中不可能是连续的。有人对低层次的事物有更深入的了解吗?
这也有一个负面的副作用,我可以很容易地运行许多程序,当所有VIRT的和超过物理内存,只要RES之和低于。然而,一旦它们都写入全局数组,系统就会耗尽物理内存,程序就会被发送到sigkill之类的地方。
理想情况下,我想告诉编译器在开始时保留全局变量和静态变量的内存。有可能吗?
编辑
@Magnus:实际上行的顺序是对的。)以第一行为例,./a.out 1000000意味着我在数组中每写第一百万个条目,因此总共只有250个条目。这与仅为1868 k的区域相对应。在最后一个示例./a.out 100中,每一个数百个条目都会被写入,然后总内存也会被物理地分配给RES=VIRT=1.9g。从数字上看,每当向数组写入条目时,物理内存上都会保留一个完整的4k块。
@Nawaz:该数组在虚拟地址空间中是连续的,但据我所知,操作系统可能很懒,在实际需要时只保留物理内存。既然这是在小块中完成的,而不是同时完成整个数组,那么如何保证它在物理内存中是连续的呢?
@Nemo:谢谢你,实际上,当调用多个a.out实例时--在开始时暂停,然后写入数组--我在/var/log/messages中得到了oom-killer消息,实际上,您的sysctrl命令首先阻止了我启动太多的a.out实例。谢谢!
Jun 1 17:49:16 localhost kernel: [32590.293421] a.out invoked oom-killer: gfp_mask=0x280da, order=0, oomkilladj=0
Jun 1 17:49:18 localhost kernel: [32592.110033] kded4 invoked oom-killer: gfp_mask=0x201da, order=0, oomkilladj=0
Jun 1 17:49:20 localhost kernel: [32594.718757] firefox invoked oom-killer: gfp_mask=0x201da, order=0, oomkilladj=0最后两行有点让人担心。:)
@doron:谢谢,很好的解释,抱歉不能投票/选择。
发布于 2011-06-01 20:20:27
这里有两件事,那就是。虚拟内存和物理内存。
用于静态数据的虚拟内存,就像在程序开始执行之前为程序分配指令一样。我的意思是,您的程序的地址总是被定义的。
然而,当涉及到将静态数据和程序指令加载到物理内存RAM时,操作系统可能很懒。这种工作方式是这样的:
进程加载器
这是一个完全轻微的操作,操作系统只允许这样做,因为它完全无法检测到正在运行的进程。当然,除非我们缺乏记忆。
发布于 2011-06-01 18:09:32
您正在查看正在提交的虚拟内存页。操作系统通常只在您的代码明确地编写或读取页面时才提交它们。这与C++无关,后者保证数组是连续的。如果您在询问如何让您的操作系统在启动时提交所有进程的页面,则需要使用特定于OS的内容(如果存在这种情况)。
发布于 2011-06-01 18:10:35
我不认为你寄出的那张桌子能证明什么是实质性的。
就静态存储数组而言,它是在程序启动之前分配的,根据定义,这意味着在程序进入main()函数之前,运行时将内存分配给全局数组,并持续到程序的持续时间:
§3.7.1/1
所有既不具有动态存储持续时间也不具有本地存储时间的对象都具有静态存储持续时间。这些对象的存储应在程序期间持续(3.6.2,3.6.3)。
无论是全局的还是局部的,数组总是有连续的内存。
https://stackoverflow.com/questions/6205681
复制相似问题