大内高手 内存模型

分享一下我老师大神的人工智能教程!零基础,通俗易懂!http://blog.csdn.net/jiangjunshow

也欢迎大家转载本篇文章。分享知识,造福人民,实现我们中华民族伟大复兴!

               

大内高手内存模型

 

转载时请注明出处和作者联系方式:http://blog.csdn.net/absurd

作者联系方式:李先静 <xianjimli at hotmail dot com>

更新时间:2007-7-9

了解linux的内存模型,或许不能让你大幅度提高编程能力,但是作为一个基本知识点应该熟悉。坐火车外出旅行时,即时你对沿途的地方一无所知,仍然可以到达目标地。但是你对整个路途都很比较清楚的话,每到一个站都知道自己在哪里,知道当地的风土人情,对比一下所见所想,旅程可能更有趣一些。

 

类似的,了解linux的内存模型,你知道每块内存,每个变量,在系统中处于什么样的位置。这同样会让你心情愉快,知道这些,有时还会让你的生活轻更松些。看看变量的地址,你可以大致断定这是否是一个有效的地址。一个变量被破坏了,你可以大致推断谁是犯罪嫌疑人。

 

Linux的内存模型,一般为:

                                                                                                                                                                                                                                                                                                                               
           

地址

           
           

作用

           
           

说明

           
           

>=0xc000 0000

           
           

内核虚拟存储器

           
           

用户代码不可见区域

           
           

<0xc000 0000

           
           

Stack(用户栈)

           
           

ESP指向栈顶

           
           

 

           
           

           

 

           

           
           

 

           

空闲内存

           
           

>=0x4000 0000

           
           

文件映射区

           
           

 

           
           

<0x4000 0000

           
           

 

           

 

           

           
           

 

           

空闲内存

           

 

           
           

 

           
           

Heap(运行时堆)

           
           

通过brk/sbrk系统调用扩大堆,向上增长。

           
           

 

           
           

.data.bss(读写段)

           
           

从可执行文件中加载

           
           

>=0x0804 8000

           
           

.init.text.rodata(只读段)

           
           

从可执行文件中加载

           
           

<0x0804 8000

           
           

保留区域

           
           

 

           

 

很多书上都有类似的描述,本图取自于《深入理解计算机系统》p603,略做修改。本图比较清析,很容易理解,但仍然有两点不足。下面补充说明一下:

 

1.         第一点是关于运行时堆的

为说明这个问题,我们先运行一个测试程序,并观察其结果:

       
           

#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

 

l         mainprint两个函数是代码段(.text)的,其地址符合表一的描述。

l         first是第一个临时变量,由于在first之前还有一些环境变量,它的值并非0xbfffffff,而是0xbfcd1264,这是正常的。

l         p0是在堆中分配的,其地址小于0x4000 0000,这也是正常的。

l         p1p2也是在堆中分配的,而其地址竟大于0x4000 0000,与表一描述不符。

 

原因在于:运行时堆的位置与内存管理算法相关,也就是与malloc的实现相关。关于内存管理算法的问题,我们在后继文章中有详细描述,这里只作简要说明。在glibc实现的内存管理算法中,Malloc小块内存是在小于0x4000 0000的内存中分配的,通过brk/sbrk不断向上扩展,而分配大块内存,malloc直接通过系统调用mmap实现,分配得到的地址在文件映射区,所以其地址大于0x4000 0000

 

maps文件中可以清楚的看到一点:

       
           

00514000-00515000 r-xp 00514000 00:00 0

           

00624000-0063e000 r-xp 00000000 03:01 718192     /lib/ld-2.3.5.so

           

0063e000-0063f000 r-xp 00019000 03:01 718192     /lib/ld-2.3.5.so

           

0063f000-00640000 rwxp 0001a000 03:01 718192     /lib/ld-2.3.5.so

           

00642000-00766000 r-xp 00000000 03:01 718193     /lib/libc-2.3.5.so

           

00766000-00768000 r-xp 00124000 03:01 718193     /lib/libc-2.3.5.so

           

00768000-0076a000 rwxp 00126000 03:01 718193     /lib/libc-2.3.5.so

           

0076a000-0076c000 rwxp 0076a000 00:00 0

           

08048000-08049000 r-xp 00000000 03:01 1307138    /root/test/mem/t.exe

           

08049000-0804a000 rw-p 00000000 03:01 1307138    /root/test/mem/t.exe

           

09f5d000-09f7e000 rw-p 09f5d000 00:00 0          [heap]

           

57e2f000-b7f35000 rw-p 57e2f000 00:00 0

           

b7f44000-b7f45000 rw-p b7f44000 00:00 0

           

bfb2f000-bfb45000 rw-p bfb2f000 00:00 0          [stack]

           

 

2.         第二是关于多线程的。

现在的应用程序,多线程的居多。表一所描述的模型无法适用于多线程环境。按表一所述,程序最多拥有上G的栈空间,事实上,在多线程情况下,能用的栈空间是非常有限的。为了说明这个问题,我们再看另外一个测试:

           

#include <stdio.h>

           

#include <pthread.h>

           

 

           

 

           

void* thread_proc(void* param)

           

{

           

    int  first = 0;

           

    int* p0 = malloc(1024);

           

    int* p1 = malloc(1024 * 1024);

           

 

           

    printf("(0x%x): first=%p/n",    pthread_self(), &first);

           

    printf("(0x%x): p0=%p p1=%p /n", pthread_self(), p0, p1);

           

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值