
ps:在Unix/Linux下,malloc底层实现就是通过系统调用sbrk实现的;在windows下malloc则是通过调用windows系统提供的接口实现。
Linux的内存模型,一般为:地址
作用
说明
>=0xc000 0000
内核虚拟存储器
用户代码不可见区域
<0xc000 0000
Stack(用户栈)
ESP指向栈顶
↓
↑
空闲内存
>=0x4000 0000
文件映射区
<0x4000 0000
↑
空闲内存
Heap(运行时堆)
通过brk/sbrk系统调用扩大堆,向上增长。
.data、.bss(读写段)
从可执行文件中加载
>=0x0804 8000(0x00008000 for arm linux)
.init、.text、.rodata(只读段)
从可执行文件中加载
<0x0804 8000(0x00008000 for arm linux)
保留区域
运行一个测试程序,观察其结果:
#include <stdio.h>
int main(int argc, char* argv[])
{
int first = 0
int* p0 = malloc(1024)
int* p1 = malloc(1024 * 1024)
int* p2 = malloc(512 * 1024 * 1024 )
int* p3 = malloc(1024 * 1024 * 1024 )
printf("main=%p print=%p\n", main, printf)
printf("first=%p\n", &first)
printf("p0=%p p1=%p p2=%p p3=%p\n", p0, p1, p2, p3)
getchar()
return 0
}
运行后,输出结果为:
main=0x8048404 print=0x8048324
first=0xbfcd1264
p0=0x9253008 p1=0xb7ec0008 p2=0x97ebf008 p3=0x57ebe008
my pc (fc5)输出结果如下:
main=0x80483f4 print=0x8048324
first=0xbf848660
p0=0x9ab2008 p1=0xb7e38008 p2=0x97e37008 p3=(nil)
arm-linux输出如下结果:
main=0x8528 print=0x8404
first=0xbec9fe10
p0=0x11008 p1=0x4005a008 p2=(nil) p3=(nil)
main和print两个函数是代码段(.text)的,其地址符合表一的描述。
first是第一个临时变量,由于在first之前还有一些环境变量,它的值并非0xbfffffff,而是0xbfcd1264,这是正常的。
p0是在堆中分配的,其地址小于0x4000 0000,这也是正常的。
但p1和p2也是在堆中分配的,而其地址竟大于0x4000 0000,与表一描述不符。
原因在于:运行时堆的位置与内存管理算法相关,也就是与malloc的实现相关。关于内存管理算法的问题,我们在后继文章中有详细描述,这里只作简要说明。在glibc实现的内存管理算法中,Malloc小块内存是在小于0x4000 0000的内存中分配的,通过brk/sbrk不断向上扩展,而分配大块内存,malloc直接通过系统调用mmap实现,分配得到的地址在文件映射区,所以其地址大于0x4000 0000。
欢迎分享,转载请注明来源:内存溢出
微信扫一扫
支付宝扫一扫
评论列表(0条)