动态内存分配如何工作?

How does dynamic memory allocation work?

考虑以下代码:

int *p = malloc(4);
int *i = malloc(4);

现在,已经分配了一块内存(上述情况下为4字节),基地址存储在p

int *i = malloc(4)行分配内存时。

编译器如何知道这块内存已分配?

为什么它没有分配与 int *p = malloc(4) 分配的相同内存块?

当您在代码中使用像 malloc 这样的例程并编译 link 您的代码为可执行程序时,软件例程库也会 link 编辑到您的代码中.该库中的例程具有用于从操作系统请求内存的软件,用于将内存分成多个部分并在使用 malloc 请求时将其发出,并用于跟踪已发出的内容和已释放的内容free.

因此,每当您编译一个非常小的程序时,您都会得到一个大型的附加软件库,人们已经开发了很多年。

编译器不负责知道谁拥有哪一块内存,也不负责不小心践踏之前分配的内存。这是操作系统的工作。编译器生成汇编代码,其中汇编代码进行适当的系统调用以从 OS 获取指向一块动态内存的指针。为了演示,这里有一个愚蠢的例子:

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

int main(void) {
    int* ptr = malloc(4);
    free(ptr);
    return 0;
}

现在编译该程序并 main 反汇编时,汇编代码如下所示:

   0x0000000100000f50 <+0>:     push   %rbp
   0x0000000100000f51 <+1>:     mov    %rsp,%rbp
   0x0000000100000f54 <+4>:     sub    [=11=]x10,%rsp
   0x0000000100000f58 <+8>:     mov    [=11=]x4,%eax
   0x0000000100000f5d <+13>:    mov    %eax,%edi
   0x0000000100000f5f <+15>:    movl   [=11=]x0,-0x4(%rbp)
   0x0000000100000f66 <+22>:    callq  0x100000f8a
   0x0000000100000f6b <+27>:    mov    %rax,-0x10(%rbp)
   0x0000000100000f6f <+31>:    mov    -0x10(%rbp),%rax
   0x0000000100000f73 <+35>:    mov    %rax,%rdi
   0x0000000100000f76 <+38>:    callq  0x100000f84
   0x0000000100000f7b <+43>:    xor    %eax,%eax
   0x0000000100000f7d <+45>:    add    [=11=]x10,%rsp
   0x0000000100000f81 <+49>:    pop    %rbp
   0x0000000100000f82 <+50>:    retq   

注意 callq 行。编译器只是负责调用适当的系统调用来获取动态内存。