当我用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与char* 等组合缺少的GCC Wform警告

从C函数调用asm函数时生成错误的BLX指令(STM32H753上的gcc)

C/C++中的状态库

va_copy的使用是未定义的行为吗?

C:fopen是如何实现二进制模式和文本模式的?

SDL 2.0-从数组渲染纹理

不同出处的指针可以相等吗?

搜索使用int代替time_t的用法

pthread_create的用法

为什么编译器不能简单地将数据从EDI转移到EAX?

UpDown控制与预期相反

在C中使用字符串时是否不需要内存分配?

在C中交换字符串和数组的通用交换函数

将数组中的所有元素初始化为 struct 中的相同值

System V 消息队列由于某种原因定期重置

使用 GCC 将一个函数中初始化的 struct 体实例通过指针传递到 C 中的另一个函数会产生不同的结果

clion.我无法理解 Clion 中发生的 scanf 错误

获取 struct 中匿名 struct 的大小

设置具有非零终止字符串的大整数