为什么动态分配的两个变量的内存位置不是连续的?

Why the Memory locations for two variables which is allocated dynamically are not consecutive?

本文关键字:位置 内存 连续 变量 两个 动态分配 为什么      更新时间:2023-10-16

我使用两个变量,其中内存是动态分配的,我打印内存位置,但它们不是连续的。 为什么?

#include <stdio.h>
#include <stdlib.h>
int main()
{
int *a = malloc(sizeof(int));
int *b = malloc(sizeof(int));
printf("n a=%p t b=%p  n",a,b);
}

我得到的答案(在 Linux 中(是

第一次:

a=0x20a0010     b=0x20a0030

第二次:

a=0x657010      b=0x657030

第三次:

a=0x139e010     b=0x139e030 

为什么ab变量的内存位置之间的确切差异是第 1 次、第 2 次和第 3 次?

这与分页内存有关吗?

我的处理器是 64 位。

两个连续分配之间的间隔与分页无关。您的分配金额非常小,因此它们位于数据细分受众群中。libc 在内部处理这些 -sizeof int字节之外的空间通常包含指向上一个和下一个数据块的指针以及分配的大小 - 毕竟free只会得到一个指针,它需要弄清楚有多少内存要解除分配。

此外,这两个指针都与 16 字节边界对齐。C11 7.22.3 说

如果分配成功,则返回的指针将适当对齐,以便可以将其分配给具有基本对齐要求的任何类型的对象的指针,然后用于访问分配空间中的此类对象或此类对象的数组(直到空间被显式解除分配(。

因此,即使您将它们用于intC 标准也要求返回的指针与任何数据类型对齐 - 在您的实现中为 16 字节。

但是,如果您分配了一个非常的对象,glibc 将使用mmap来映射整个页面。然后对齐方式(在我的 64 位计算机上(正好是 16K 页面开头的 4 个字节:

#include <stdio.h>
#include <stdlib.h>
int main()
{
int *a = malloc(12345678);
int *b = malloc(12345678);
printf("n a=%p t b=%p  n",a,b);
}

运行时

% ./a.out  
a=0x7fb65e7b7010     b=0x7fb65dbf0010

人们可以看到带有strace ./a.outmmap调用 - 在其他系统调用中,有

mmap(NULL, 12349440, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fb65e7b7000
mmap(NULL, 12349440, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fb65dbf0000

至于为什么地址从一个执行不断变化到另一个执行 - 这是由于地址空间布局随机化或ASLR - 一种安全机制,使邪恶破解者更难预测利用代码中的未定义行为


附言如果确实需要在连续地址动态分配 2ints 的空间,请分配一个数组。

操作系统处理内存分配,并且在动态分配两个连续变量时,无法保证此内存是连续的。我还应该提到,这是被称为ASLR的防御机制的结果。ASLR 通过在进程执行期间随机化进程的位置来防止缓冲区溢出,这可能包括堆栈、堆和库。这就是您注意到这些地址更改的原因。按照标准,您只能保证以下内容。

ISO C11 7.22.3.4 马洛克

1(剧情简介

#include <stdlib.h>
void* malloc(size_t size);

2(描述malloc 函数为大小由大小指定且其值不确定的对象分配空间。

3(退货malloc 函数返回空指针或指向已分配空间的指针。

正如 GNU 中注释的那样 malloc 的例子

请注意,位于块末尾之后的内存可能会 用于其他用途;也许是已经分配的块 另一个打电话给马洛克。

这实际上意味着,对于每次调用malloc操作系统,根据其内存管理算法,为调用方找到最合适/适当/最合适的/有效的可用空间。

例如:

void* p_1 = malloc(4);
void* p_2 = malloc(4);
[oooo][xxxx][oooo][oooo]
^           ^
p_1         p_2