首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何以及何时分配全局或静态数组的内存?

如何以及何时分配全局或静态数组的内存?
EN

Stack Overflow用户
提问于 2011-06-01 18:04:09
回答 4查看 1.2K关注 0票数 4

在c++中定义全局或静态数组时,它的内存不是在程序开始时立即保留的,而是只在我们向数组写入一次时才保留。我发现令人惊讶的是,如果我们只写到数组的一小部分,它仍然没有保留整个内存。考虑以下示例,它稀疏地写入全局数组:

代码语言:javascript
复制
#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的输出,例如:

代码语言:javascript
复制
./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.out

RES列表示仅在小块中保留内存,这也意味着数组在物理内存中不可能是连续的。有人对低层次的事物有更深入的了解吗?

这也有一个负面的副作用,我可以很容易地运行许多程序,当所有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实例。谢谢!

代码语言:javascript
复制
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:谢谢,很好的解释,抱歉不能投票/选择。

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2011-06-01 20:20:27

这里有两件事,那就是。虚拟内存和物理内存。

用于静态数据的虚拟内存,就像在程序开始执行之前为程序分配指令一样。我的意思是,您的程序的地址总是被定义的。

然而,当涉及到将静态数据和程序指令加载到物理内存RAM时,操作系统可能很懒。这种工作方式是这样的:

进程加载器

  • 为静态数据分配进程虚拟内存,但不将数据加载到内存中。当您尝试访问这些地址时,
  • 会触发一个处理器异常,然后进入内核模式。内核
  • 现在将数据加载到RAM中,并将其链接到进程虚拟地址空间。
  • 内核切换回用户模式,到处理器异常发生的确切位置。由于
  • 现在被链接到进程虚拟地址空间中,程序现在将继续执行,就好像什么都没有发生过一样。

这是一个完全轻微的操作,操作系统只允许这样做,因为它完全无法检测到正在运行的进程。当然,除非我们缺乏记忆。

票数 2
EN

Stack Overflow用户

发布于 2011-06-01 18:09:32

您正在查看正在提交的虚拟内存页。操作系统通常只在您的代码明确地编写或读取页面时才提交它们。这与C++无关,后者保证数组是连续的。如果您在询问如何让您的操作系统在启动时提交所有进程的页面,则需要使用特定于OS的内容(如果存在这种情况)。

票数 6
EN

Stack Overflow用户

发布于 2011-06-01 18:10:35

我不认为你寄出的那张桌子能证明什么是实质性的。

就静态存储数组而言,它是在程序启动之前分配的,根据定义,这意味着在程序进入main()函数之前,运行时将内存分配给全局数组,并持续到程序的持续时间:

§3.7.1/1

所有既不具有动态存储持续时间也不具有本地存储时间的对象都具有静态存储持续时间。这些对象的存储应在程序期间持续(3.6.2,3.6.3)。

无论是全局的还是局部的,数组总是有连续的内存。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/6205681

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档