正如一些程序员花花公子刚才所说,C 规范没有规定必须放置自动变量的区域。但是编译器通常会增加堆栈以适应它们。但是,它们可能会在 .data 区域结束,如果它们被定义为 static char *pointer1,它们就会结束。
初始化值可能存在也可能不存在于程序区域中。在您的情况下,由于值的类型是int,如果具有适当内联运算符的指令可用,大多数架构会将初始化内联为适当的机器指令。例如,在 x86_64 中,将发出单个 mov/movq 操作以将 0 (NULL) 或其他 int 放入堆栈上的适当内存位置。
但是,使用全局范围初始化的变量,例如 static char string[40] = "Hello world" 或其他已初始化的全局变量最终会出现在 .data 区域并占用其中的空间。编译器可能会将已声明但未定义的全局范围变量放在 .bss 区域中。
问题既然pointer1 = malloc(80),它是否属于堆栈部分?这个问题定义不明确,因为它包含两个东西。
值pointer1 是一个将保存在&pointer1 的值。考虑到上述考虑,编译器可能已放入堆栈的地址。
malloc(80) 的结果是一个值,它引用堆上的一个区域,一个不同的区域,在映射的程序空间之外动态分配。
在 Linux 上,调用 malloc 的结果甚至可能会创建一个新的 NULL 支持的内存区域(即不是永久存储在文件中的临时区域;尽管它可以被内核交换)。
本质上,您可以将 malloc(80) 的行为方式想象成类似(不考虑 free(),所以 这是过于简单化了):
int space_left = 0; void *last_mapping = NULL;
void *malloc(int req) {
void *result;
if (space_left < req) {
last_mapping = mmap(NULL, MALLOC_CHUNK_LENGTH, PROT_READ|PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
space_left = MALLOC_CHUNK_LENGTH;
}
space_left -= req;
result = last_mapping;
last_mapping += req;
return result;
}
使用 MAP_PRIVATE 调用 malloc 和 mmap 的巨大区别在于 mmap 是一个 Linux 系统调用,它必须进行内核上下文切换,分配新的内存映射并为每个分配的内存块重置 MMU 层,而 malloc 可以更智能,将单个大区域用作“堆”,并在堆初始化后管理用户空间中的不同 malloc 和 free (直到堆空间用完,它可能必须管理多个堆)。