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

Why doesn't the size of the binary file increase with the size of the static data?

提问人:richardIII 提问时间:11/2/2023 更新时间:11/2/2023 访问量:75

问:

当我编译以下 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;
}

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

C 静态内存

评论

2赞 Eugene Sh. 11/2/2023
它已打开,并且已零初始化。因此,二进制文件不必将初始化数据保留在其中。它只是保留“指令”,以便在加载后保留此内存。.bss
0赞 richardIII 11/2/2023
@EugeneSh。我明白了,数组是否会加载到 RAM 中以执行初始化循环?
0赞 Eugene Sh. 11/2/2023
是的,除非优化,否则此内存将保留给该过程,这是可能的。
1赞 Lundin 11/2/2023
与 in 不同,数据不需要存储在可执行文件中。试着看看是否有区别。.bss.datachar bytes[1000*1000*1000] = { 1 };

答:

5赞 ikegami 11/2/2023 #1

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

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

$ 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)

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

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

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

4赞 Eric Postpischil 11/2/2023 #2

定义的数组以数据的形式呈现在二进制中,表示有一个具有一定大小的程序部分,并且要用零初始化。(大小将是累积到此程序部分的所有对象的总和,包括所需的任何填充。当您增加或减少此类数组的大小并重建二进制文件时,唯一需要更改的是该大小的数字。实际上,二进制文件中不需要有直接对应于数组中字节的字节。char bytes[1000*1000*1000];

需要时(例如,当程序尝试使用此程序部分中的数据时),操作系统将为该程序部分(或其中的一部分)提供内存,并确保它以零初始化。