【问题标题】:Why the Memory locations for two variables which is allocated dynamically are not consecutive? [duplicate]为什么动态分配的两个变量的内存位置不连续? [复制]
【发布时间】:2018-01-03 23:52:37
【问题描述】:

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

#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 位的。

【问题讨论】:

  • 这有关系吗?如果你需要连续的地址,你应该使用一个数组。
  • 虽然这是误导,但这是一个有趣的问题。没有别的,你可能期望内存位置是连续的
  • 您的地址相隔32 字节。如果它们是连续的,你会期望它们相隔 4 字节(假设 sizeof(int) == 4,它似乎通常是这样)
  • malloc() 分配的不仅仅是请求的字节数,因为它必须在内存块中存储额外的跟踪信息,因此free() 知道如何正确释放内存。想想看。您正在分配 sizeof(int) 字节。如果您不将sizeof(int) 作为参数传递给它,您认为free() 如何知道释放sizeof(int) 字节?该信息必须存储在某个地方,传递给free() 的唯一内容是内存指针,因此该信息必须位于内存块本身中。
  • 正如@RemyLebeau 所说,让malloc() 只分配一定大小或更大的块也确实更有效率;如果您要求更小的尺寸,它可以升级到这个更大的尺寸

标签: c++ c linux


【解决方案1】:

两次连续分配之间的差距与分页无关。您的分配是如此之小,以至于它们驻留在数据段中。 Libc 在内部处理这些 - 你的 sizeof int 字节之外的空间通常包含指向前一个和下一个数据块的指针以及分配的大小 - 毕竟 free 只会得到一个指针,它需要弄清楚多少要释放的内存。

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

如果分配成功返回的指针是适当对齐的,因此它可以被分配给指向具有基本对齐要求的任何类型对象的指针,然后用于在分配的空间中访问此类对象或此类对象的数组(直到空间被显式释放)。

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

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

#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

可以看到mmap 调用strace ./a.out - 除了其他系统调用之外,还有

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

至于为什么地址从一个执行到另一个执行不断变化 - 这是由于address space layout randomization, or ASLR - 一种安全机制,使邪恶的破解者更难可预测地利用未定义的行为 在你的代码中。


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

【讨论】:

  • 那么为什么每次指针值都不一样呢?
  • @EJP 也添加了这一点
  • 谢谢@antti haapala .. 但我不希望那个记忆是连续的.. 为什么它不连续是我的问题.. 以及我第一次提到我的记忆位置我执行程序的第 2 次和第 3 次.. 如果您观察到内存位置的位置和差异 b/w 已分配.. 如果发现一些模棱两可...
  • 嗯,我上面也回答过了
  • 谢谢@antti haapala .. 我没有正确阅读...这是我的错误.. 非常感谢 :-)
【解决方案2】:

操作系统处理内存分配,动态分配两个连续变量时,不能保证这块内存是连续的。我还应该提到,这是一种称为ASLR 的防御机制的结果。 ASLR 通过在进程执行期间随机化进程的位置来防止缓冲区溢出,这可能包括stack, heap, and libraries。这就是您注意到这些地址发生变化的原因。按照标准,您只能得到以下保证。

ISO C11 7.22.3.4 Malloc

1) 概要

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

2) 说明 malloc 函数为大小由 size 指定且值不确定的对象分配空间。

3) 返回 malloc 函数返回空指针或指向分配空间的指针。

【讨论】:

【解决方案3】:

GNU Examples of malloc的注释

注意,位于块末尾之后的内存可能 用于其他用途;也许已经分配了一个块 再次调用 malloc。

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

例如:

void* p_1 = malloc(4);
void* p_2 = malloc(4);

[oooo][xxxx][oooo][oooo]
^           ^
p_1         p_2

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-10-29
    • 2016-10-19
    • 2020-09-26
    • 2011-01-15
    • 2015-01-27
    • 1970-01-01
    • 2017-12-21
    • 1970-01-01
    相关资源
    最近更新 更多