【发布时间】:2013-10-18 17:56:04
【问题描述】:
每当您研究进程的内存分配时,您通常会看到它的概述如下:
到目前为止一切顺利。
但是你有 sbrk() 系统调用,它允许程序更改其数据部分的上限,它也可以用于简单地检查限制在哪里 sbrk( 0)。使用该功能,我发现了以下模式:
模式 1 - 小型 malloc
我在我的 Linux 机器上运行以下程序:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int globalVar;
int main(){
int localVar;
int *ptr;
printf("localVar address (i.e., stack) = %p\n",&localVar);
printf("globalVar address (i.e., data section) = %p\n",&globalVar);
printf("Limit of data section = %p\n",sbrk(0));
ptr = malloc(sizeof(int)*1000);
printf("ptr address (should be on stack)= %p\n",&ptr);
printf("ptr points to: %p\n",ptr);
printf("Limit of data section after malloc= %p\n",sbrk(0));
return 0;
}
输出如下:
localVar address (i.e., stack) = 0xbfe34058
globalVar address (i.e., data section) = 0x804a024
Limit of data section = 0x91d9000
ptr address (should be on stack)= 0xbfe3405c
ptr points to: 0x91d9008
Limit of data section after malloc= 0x91fa000
正如您所见,分配的内存区域正好在旧数据段限制之上,并且在 malloc 之后该限制被向上推,因此分配的区域实际上位于新数据段内。
问题 1:这是否意味着小型 malloc 会在数据段分配内存而根本不使用堆?
模式 2 - 大 Malloc
如果在第 15 行增加请求的内存大小:
ptr = malloc(sizeof(int)*100000);
您现在将得到以下输出:
localVar address (i.e., stack) = 0xbf93ba68
globalVar address (i.e., data section) = 0x804a024
Limit of data section = 0x8b16000
ptr address (should be on stack)= 0xbf93ba6c
ptr points to: 0xb750b008
Limit of data section after malloc= 0x8b16000
正如您在此处看到的,数据段的限制没有改变,而是分配的内存区域位于间隙段的中间,在数据段和堆栈之间。
问题 2:这是否是实际使用堆的大型 malloc?
问题 3:对此行为有何解释?我发现它有点不安全,因为在第一个示例(小 malloc)中,即使在您释放分配的内存之后,您仍然可以使用指针并使用该内存而不会出现段错误,因为它将在您的数据中部分,这可能会导致难以检测到错误。
规格更新:Ubuntu 12.04,32 位,gcc 版本 4.6.3,Linux 内核 3.2.0-54-generic-pae。
更新 2:罗德里戈的回答解决了这个谜团。 This Wikipedia link 也有帮助。
【问题讨论】:
-
所有这些“如果 Y 发生,X 会发生”问题都是理论上的,实际上无法回答,而无需提及具体的实现。什么Linux?哪个编译器?哪个标准库实现?什么 CPU?
-
@H2CO3,你是说你确定上述行为是依赖于实现的,而不是 Linux 内核的标准吗?因为如果这是 Linux 内核的标准,那么规格就不重要了,对吧?无论哪种方式,为了完整起见,我都将它们包括在内。
-
@H2CO3 我同意。尽管如此,我还是觉得这种行为很奇怪(不是吗?),所以让我们看看是否有人对此有更多线索。
-
我的理解是
malloc对用户空间中的堆进行内存管理——根据需要从操作系统释放或请求大块内存(即试图减少昂贵的上下文切换)。我还认为 malloc 确实请求了可用于该操作系统/硬件的内存块。 -
请记住,许多堆管理器会将非常大的分配(通常超过 16M 左右)放置在与其他“段”不同的“段”中,地址中的高位组明显不同.堆栈和堆位于不同的段中并不少见。上图非常简单明了(并且是一个很好的概念视图),但通常不能反映现实。
标签: c pointers memory-management malloc heap-memory