zoukankan      html  css  js  c++  java
  • 大内高手—内存模型

    大内高手内存模型

     

    转载时请注明出处和作者联系方式: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);

     

        return 0;

    }

     

    #define N 5

    int main(int argc, char* argv[])

    {

        int first = 0;

        int i= 0;

        void* ret = NULL;

        pthread_t tid[N] = {0};

     

        printf("first=%p/n", &first);

        for(i = 0; i < N; i++)

        {

            pthread_create(tid+i, NULL, thread_proc, NULL);

        }

     

        for(i = 0; i < N; i++)

        {

            pthread_join(tid[i], &ret);

        }

     

        return 0;

    }

     

    运行后,输出结果为:

    first=0xbfd3d35c

    (0xb7f2cbb0): first=0xb7f2c454

    (0xb7f2cbb0): p0=0x84d52d8 p1=0xb4c27008

    (0xb752bbb0): first=0xb752b454

    (0xb752bbb0): p0=0x84d56e0 p1=0xb4b26008

    (0xb6b2abb0): first=0xb6b2a454

    (0xb6b2abb0): p0=0x84d5ae8 p1=0xb4a25008

    (0xb6129bb0): first=0xb6129454

    (0xb6129bb0): p0=0x84d5ef0 p1=0xb4924008

    (0xb5728bb0): first=0xb5728454

    (0xb5728bb0): p0=0x84d62f8 p1=0xb7e2c008

     

    我们看一下:

    主线程与第一个线程的栈之间的距离:0xbfd3d35c - 0xb7f2c454=0x7e10f08=126M

    第一个线程与第二个线程的栈之间的距离:0xb7f2c454 - 0xb752b454=0xa01000=10M

    其它几个线程的栈之间距离均为10M

    也就是说,主线程的栈空间最大为126M,而普通线程的栈空间仅为10M,超这个范围就会造成栈溢出。

     

    栈溢出的后果是比较严重的,或者出现Segmentation fault错误,或者出现莫名其妙的错误。

     

  • 相关阅读:
    URAL——DFS找规律——Nudnik Photographer
    URAL1353——DP——Milliard Vasya's Function
    URAL1203——DPor贪心——Scientific Conference
    递推DP HDOJ 5389 Zero Escape
    区间DP UVA 1351 String Compression
    树形DP UVA 1292 Strategic game
    Manacher HDOJ 5371 Hotaru's problem
    同余模定理 HDOJ 5373 The shortest problem
    递推DP HDOJ 5375 Gray code
    最大子序列和 HDOJ 1003 Max Sum
  • 原文地址:https://www.cnblogs.com/zhangyunlin/p/6167876.html
Copyright © 2011-2022 走看看