当我用gcc -O0编译下面的C代码时,

#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. 我分配的1 GB在哪里?它不在堆上,因为我不调用Malloc,也不在堆栈上,因为它太多了.

推荐答案

因为该区域是用零初始化的,所以在某些系统上它不需要是二进制的.加载器将简单地告诉OS内存空间的某些部分将被标记为已分配,并且OS将提供必要的归零页面.

在x86_64上的Linux上使用GCC编译您的程序(AS 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)

它不仅不会占用二进制文件中的空间,而且可能会占用非常少的RAM.

在具有虚拟内存的系统(如台式机,平板电脑和手机)上,实际上可能会分配一个比系统的实际RAM大得多的零初始化静态array.这在这样的系统上是可能的,因为操作系统只需要在它开始被修改时开始花费实际资源.即使这样,它也可能只需要为被修改的特定内存页面(例如4 KiB部分)花费资源.

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

C++相关问答推荐

不同到达时间的轮询实现

使用单个字节内的位字段

*p[num]和(*p)num的区别

特定闪存扇区的内存别名

难以理解Makefile隐含规则

变量>;-1如何在C中准确求值?

Ruby C Api处理异常

用C宏替换strncMP函数中的参数

为什么memcpy进入缓冲区和指向缓冲区的指针工作相同?

CGO:如何防止在使用CGO在包中包含C头文件时出现多个定义...&q;错误?

在句子中转换单词的问题

如何在C中只对字符串(包含数字、单词等)中的数字进行重复操作?

为什么用非常数指针变量改变常量静态变量时会出现分段错误?

S和查尔有什么不同[1]?

我在C程序的Flex/Bison中遇到语法错误

生成一个半RNG,结果用C表示(无随机/随机)

是否有单独的缓冲区用于读写库调用?

为什么GCC不能在 struct 初始值设定项中以sizeof作为条件的三进制中处理复合文字的编译时求值?

在C中,为什么这个带有递增整数的main函数从不因溢出而崩溃?

如何正确探测平台设备?