zoukankan      html  css  js  c++  java
  • Linux的Application 内存模型---

    Linux的内存模型,一般为:

     

    现在的每个进程使用了全部4G线性空间。在加载程序时内核把程序加载到线性地址0x08048000开始的位置。这个位置当然>128MB。2G开始是共享库,3G开始是内核。

     

     

    地址------------------------作用--------------------------说明

     

     

     

    >=0xc0000000---------内核虚拟存储器-------------用户代码不可见区域

     

    < 0xc0000000----------Stack(用户栈)------------ESP指向栈顶,向下增长

     

    -------------------------------------------------空闲内存

     

    >=0x40000000---------文件映射区------------------mmap的空间

     

    < 0x40000000-------------------------------------空闲内存

     

    ---------------------Heap(运行时堆)--------------通过brk/sbrk系统调用扩大堆,向上增长。

     

    ---------------------.data、.bss(读写段)---------从可执行文件中加载

     

    >=0x08048000---------.init、.text、.rodata-------从可执行文件中加载

     

    < 0x08048000---------保留区域--------------------

    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         main和print两个函数是代码段(.text)的,其地址符合表一的描述。

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

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

    l         但p1和p2也是在堆中分配的,而其地址竟大于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错误,或者出现莫名其妙的错误。

  • 相关阅读:
    0206-leetcode算法实现-反转链表reverse-linked-list-python&golang实现
    Elasticsearch集群角色类型node.master及node.data
    linux cache缓存过大导致内存资源不够用
    helm v3 调试 k8s elasticsearch集群(5)
    0203-leetcode算法实现之移除链表元素-remove-linked-list-elements-python&golang实现
    算法学习步骤
    conda 安装的坑
    matplotlib Demo
    pandas小demo
    深度学习常见问题
  • 原文地址:https://www.cnblogs.com/SZLLQ2000/p/5108833.html
Copyright © 2011-2022 走看看