为什么二进制文件的大小不会随着静态数据的大小而增加?

2 c memory static

当我用 编译以下 C 代码时gcc -O0

#include <stdlib.h>
#include <stdio.h>

char bytes[1000*1000*1000];

int main(void) {
    for (int i = 0; i < 1000*1000; i++)
        bytes[i] = (char) i;
    printf("%c\n", bytes[56789]);
    return EXIT_SUCCESS;
}
Run Code Online (Sandbox Code Playgroud)

二进制文件只有 16kB。我分配的1GB去哪儿了?它不在堆上,因为我不调用 malloc,也不在堆栈上,因为它太多了。

ike*_*ami 5

由于该区域是用零初始化的,因此在某些系统上不需要位于二进制文件中。加载程序将简单地告诉操作系统内存空间的某些部分将被标记为已分配,并且操作系统将提供必要的清零页面。

在 x86_64 上的 Linux 上使用 gcc编译程序(如a)后,您可以看到一个“指令”来A分配 1,000,000,032 ( 3b9aca20) 字节。NOBITS指的是它不在二进制文件中的事实。

$ readelf -S a
There are 31 section headers, starting at offset 0x3998:

Section Headers:
  [Nr] Name              Type             Address           Offset
       Size              EntSize          Flags  Link  Info  Align
...
  [26] .bss              NOBITS           0000000000004020  00003010
       000000003b9aca20  0000000000000000  WA       0     0     32
...
Key to Flags:
  W (write), A (alloc), X (execute), M (merge), S (strings), I (info),
  L (link order), O (extra OS processing required), G (group), T (TLS),
  C (compressed), x (unknown), o (OS specific), E (exclude),
  l (large), p (processor specific)
Run Code Online (Sandbox Code Playgroud)

它不仅不占用二进制空间,而且可能只占用很少的 RAM。

在具有虚拟内存的系统(例如台式机、平板电脑和手机)上,实际上可以分配远大于系统实际 RAM 的零初始化静态数组。在这样的系统上这是可能的,因为操作系统只需要在开始修改后就开始在其上花费实际资源。即便如此,它可能只需要为修改的特定内存页面(例如 4 KiB 部分)花费资源。

您仍然会受到进程地址空间的限制,但在 64 位系统上这实际上是无限的。