• 代码中数据存储的位置


    一个由 c/c++编译过的程序占用的内存分为以下几个部分:
    1. 栈区:就是那些由编译器在需要的时候分配,在不需要的时候自动清除的变量的存储区。里面的变量通常是局部变量、函数参数等。

    2. 堆区(动态内存分配):通过new和malloc分配,由delete或free手动释放或者程序结束自动释放。动态内存的生存期人为决定,使用灵活。缺点是容易分配/释放不当容易造成内存泄漏,频繁分配/释放会产生大量内存碎片。 若程序员不释放,程序结束时可能由OS(操作系统)回收。注意它与数据结构中的堆是两回事,分配方式类似于链表。

    3.全局区(静态区)static :全局变量和静态变量的存储是放在一块的。在以前的C语言中,全局变量又分为初始化的和未初始化的,在C++里面没有这个区分了,他们共同占用同一块内存区。程序结束后由系统释放。

    4.常量存储区:这是一个比较特殊的存储区,里面存放的是常量,不允许修改。程序结束后由系统释放。

    5. 程序代码区:存放函数的二进制代码。
    下面说一下栈存储和堆存储的区别:
        栈存储:栈存储通常用于存储占用空间小,生命周期短的数据,如局部变量和参数变量等。只要栈的剩余空间大于所申请空间,系统将为程序提供内存,否则将报异常提示栈溢出。

        堆存储:由于大量new/delete的使用,容易造成大量的内存碎片;由于没有专门的系统支持,效率很低;由于可能引发用户态和核心态的切换,内存的申请,代价变得更加昂贵。首先应该知道操作系统有一个记录空闲内存地址的链表,当系统收到程序的申请时, 会遍历该链表,寻找第一个空间大于所申请空间的堆结点,然后将该结点从空闲结点链表中删除,并将该结点的空间分配给程序,另外,对于大多数系统,会在这块内存空间中的首地址处记录本次分配的大小,这样,代码中的delete语句才能正确的释放本内存空间。另外,由于找到的堆结点的大小不一定正好等于申请的大小,系统会自动的将多余的那部分重新放入空闲链表中。

    在地址分配方面:对于堆来讲,向着内存地址增加的方向;对于栈来讲,向着内存地址减小的方向增长。(联系:小尾端是高位字节在高端地址、低位字节在低位地址,因此在压栈时先压高字节后压低字节)。

    分配效率:栈是机器系统提供的数据结构,计算机会在底层对栈提供支持:分配专门的寄存器存放栈的地址,压栈出栈都有专门的指令执行,这就决定了栈的效率比较高。堆则是C/C++函数库提供的,它的机制是很复杂的,例如为了分配一块内存,库函数会按照一定的算法(具体的算法可以参考数据结构/操作系统)在堆内存中搜索可用的足够大小的空间,如果没有足够大小的空间(可能是由于内存碎片太多),就有可能调用系统功能去增加程序数据段的内存空间,这样就有机会分到足够大小的内存,然后进行返回。显然,堆的效率比栈要低得多。

    不同的compiler在编译的过程中对于存储的分配可能略有不同,但基Text段、Data段和BSS段本结构大致相同。

    大体上可分为三段:Text段、Data段和BSS段

    text段用于存放代码,通常情况下在内存中被映射为只读,但data和bss是可写的。

    数据存放通常分成如下几个部分:

    1、stack:由编译器自动分配,保存函数的局部变量和参数。是用户存放程序临时创建的局部变量,

      也就是说我们函数括弧“{}”中定义的变量(但不包括static声明的变量,static意味着在数据段中存放变量)。

      除此以外,在函数被调用时,其参数也会被压入发起调用的进程栈中,并且待到调用结束后,函数的返回值也会被存放回栈中。

      由于栈的先进先出(FIFO)特点,所以栈特别方便用来保存/恢复调用现场。

      从这个意义上讲,我们可以把堆栈看成一个寄存、交换临时数据的内存区。

    2、heap:一般由程序员动态分配释放, 若程序员不释放,程序结束时可能由OS回收 ,例如malloc。它不同与数据结构中的堆,它更类似于链表。

    3、全局区:全局变量和静态变量的存储是放在一块的,初始化的全局变量和静态变量在一块区域。

    4、文字常量区:这一区域很多情况下在代码区,因为代码段和常量一样是只读的。

    5、程序代码区:存放函数体的二进制代码。

    6、bss段:定义而没有赋初值的全局变量和静态变量,放在这个区域,通常只是记录变量名和大小,相当于一个占位符。

    bss段属于静态内存分配。 

    data段属于静态内存分配。 

    一个程序本质上都是由 bss段、data段、text段三个组成的。

      这样的概念,不知道最初来源于哪里的规定,但在当前的计算机程序设计中是很重要的一个基本概念。

      而且在嵌入式系统的设计中也非常重要,牵涉到嵌入式系统运行时的内存大小分配,存储单元占用空间大小的问题。

        在采用段式内存管理的架构中(比如intel的80x86系统),bss段通常是指用来存放程序中未初始化的全局变量的一块内存区域,

      一般在初始化时bss 段部分将会清零。bss段属于静态内存分配,即程序一开始就将其清零了。

        比如,在C语言之类的程序编译完成之后,已初始化的全局变量保存在.data 段中,未初始化的全局变量保存在.bss 段中。

      text和data段都在可执行文件中(在嵌入式系统里一般是固化在镜像文件中),由系统从可执行文件中加载;

      而bss段不在可执行文件中,由系统初始化。

    //查看代码中各数据存储位置
    //查看c程序执行时的内存分配情况
    #include<stdio.h>
    #include<stalib.h>
    int a=0; //a在全局已初始化数据区
    char *p0; //p0在BSS区(未初始化全局变量)
    int main(void)
    {
    int b; //b在栈区
    char s[]=“abc”; //s在栈区,"abc"在已初始化数据区
    char *p1,*p2; //p1 p2在栈区
    char *p3=“123456”; //123456字符串在已初始化数据区,p3在栈区
    static int c=0; //c为全局(静态)数据,存在于已初始化数据区
    p1=(char *)malloc(10); //分配得来的10字节的区域在堆区
    p2=(char *)malloc(20); //分配得来的20字节的区域在堆区
    free(p1);
    free(p2);
    p1=NULL;
    p2=NULL;
    }
    Linux程序存储结构
    https://blog.csdn.net/Aseed40424991/article/details/105924252
    参考:

    http://www.360doc.com/content/18/0127/15/48169514_725531488.shtml

    https://blog.csdn.net/nyist_zxp/article/details/80257760

  • 相关阅读:
    Java----自增,自减运算符
    Java----运算符
    Java---变量,常量,作用域
    Java--类型转换
    图像压缩
    最大熵对应的概率分布
    Python matplotlib画图时图例说明(legend)放到图像外侧详解
    pytorch persistent_workers
    RuntimeError: one of the variables needed for gradient computation has been modified by an inplace operation
    Pytorch中出现的奇怪错误
  • 原文地址:https://www.cnblogs.com/klb561/p/14841975.html
Copyright © 2020-2023  润新知