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

标签 c++ arrays static global contiguous

当在 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.out

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

这也有负面影响,只要 RES 的总和低于物理内存,我就可以轻松运行许多程序,其中所有 VIRT 的总和超过物理内存。然而,一旦它们全部写入全局数组,系统就会耗尽物理内存,并且程序会被发送 sigkill 或其他东西。

理想情况下,我想告诉编译器在开始时保留全局变量和静态变量的内存。可能吗?

编辑

@Magnus:这些行的顺序实际上是正确的。 :) 以第一行为例,./a.out 1000000 表示我在数组中每百万分之一写入一个条目,因此总共只有 250 个。这对应于仅为 1868k 的 RES。在最后一个示例中,./a.out 100 每写入一百个条目,然后物理分配的总内存也为 RES=VIRT=1.9g。从数字看来,无论何时将一个条目写入数组,都会在物理内存上保留一个完整的 4k block 。

@Nawaz:该数组在虚拟地址空间中是连续的,但据我所知,操作系统可能是惰性的,只在实际需要时才保留物理内存。由于这是在小块中完成的,而不是一次完成整个数组,如何保证它在物理内存中是连续的?

@Nemo:谢谢,确实在调用 a.out 的多个实例时,它在开头暂停然后写入数组,我收到了 oom-killer 消息在 /var/log/messages 中,实际上您的 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:谢谢,很好的解释,抱歉不能投票/选择。

最佳答案

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

关于c++ - 如何以及何时分配全局或静态数组的内存?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6205681/

相关文章:

java - 等同于 Java 的 System.getProperty ("java.io.tmpdir") 在 C 中?

c++ - Bool 标志与 Unsigned Char 标志

arrays - 使用循环将 BYTE 数组读入 DWORD 数组

c++ - 在其声明文件之外使用对象 (C++)

c++ - 如何将用 C++ 编写的 Qt4 小部件实现到一些 Python 代码中?

C++ 将串行输入读取到字符串

java - 斐波那契递归问题,无法返回 2 个元素

javascript - 从 SELECT 中的多个选择中获取值

java - 蓝J错误: Non-static method(OOPoint) cannot be referenced from a static context

java - 进入main方法后执行的静态 block