动态存储区、静态存储区、堆和栈的区别

2023-05-16

C/c++程序经过编译连接后形成的二进制映像文件,这文件包含:

栈,堆,数据段(只读数据段,已经初始化读写数据段,未初始化数据段即BBS)和代码段组成.


                                                           

1.栈区(stack):

由编译器自动分配释放,存放函数的参数值局部变量等值。其操作方式类似于数据结构中的栈。

2.堆区(heap):

堆允许程序在运行时动态地申请某个大小的内存。

一般由程序员分配释放,若程序员不释放,则可能会引起内存泄漏。

注堆和数据结构中的堆栈不一样,其类是与链表。

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

所有的语句编译后会生成CPU指令存储在代码区.

4.数据段:由三部分组成:

<1>只读数据段
只读数据段是程序使用的一些不会被更改的数据,使用这些数据的方式类似查表式的操作,由于这些变量不需要更改,因此只需要放置在只读存储器中即可。一般是const修饰的变量以及程序中使用的文字常量一般会存放在只读数据段中。
<2>已初始化的读写数据段:
已初始化数据是在程序中声明,并且具有初值的变量,这些变量需要占用存储器的空间,在程序执行时它们需要位于可读写的内存区域内,并且有初值,以供程序运行时读写。在程序中一般为已经初始化的全局变量已经初始化的静态局部变量(static修饰的已经初始化的变量)
<3>未初始化段(BSS):
[
BSS段通常是指用来存放程序中未初始化的全局变量和静态变量的一块内存区域。
特点是可读写的,在程序执行之前BSS段会自动清0。
]

未初始化数据是在程序中声明,但是没有初始化的变量,这些变量在程序运行之前不需要占用存储器的空间。与读写数据段类似,它也属于静态数据区。但是该段中数据没有经过初始化。未初始化数据段只有在运行的初始化阶段才会产生,因此它的大小不会影响目标文件的大小。在程序中一般是没有初始化的全局变量没有初始化的静态局部变量

附加说明:

常量区(特殊的常量存储区,属于静态存储区)
  1) 常量占用内存,只读状态,决不可修改
  2) 常量字符串就是放在这里的,程序结束后由系统释放

-----------------------------------------------------------------------------------------------------------------

动态存储方式
所谓动态存储方式是指在程序运行期间根据需要进行动态的分配存储空间的方式。
动态存储变量是在程序执行过程中,使用它时才分配存储单元, 使用完毕立即释放。 
典型的例子是函数的形式参数,在函数定义时并不给形参分配存储单元,只是在函数被调用时,才予以分配,调用函数完毕立即释放。如果一个函数被多次调用,则反复地分配、释放形参变量的存储单元。
-----------------------------------------------------------------------------------------------------------------
动态存储区:
1.栈和堆

栈:会存放函数的返回地址、参数和局部变量。

堆:我们通过 new 算符和 malloc 函数分配得到的空间。

堆和栈在内存中分配位置,跟硬件架构和操作系统都有关系。
x86中栈都是由高地址向低地址分配,堆是由低地址向高地址分配,不过在 Windows 和 Linux 中堆和栈的位置相反,另外存放静态数据、代码的区域位置也有一些不同。
栈是属于线程的,每一个线程会有一个自己的栈。
2.局部自动变量
存放在栈区,在栈区里面其实又可以分成好几个区域,他们叫做栈桢,一个栈桢就是一个函数,需要调用该函数的时候就如入栈,函数return的时候就会弹出栈,所以他们的生命周期是从函数的开始直到函数结束。
而栈帧里面又存放着什么呢,栈帧存放着以下几种东西:参数变量的地址,局部变量的地址,return的地址(还有栈指针和基指针,想知道这个是就什么百度吧)
3.自动变量(未加static声明的局部变量) ;
4.函数调用时的现场保护和返回地址等;
5.动态变量

通常是由malloc new等分配的空间,生命周期是从分配的那一刻直到free结束。
-----------------------------------------------------------------------------------------------------------------
静态存储方式
所谓静态存储方式是指在程序编译期间分配固定的存储空间的方式。
该存储方式通常是在变量定义时就分定存储单元并一直保持不变, 

直至整个程序结束。全局变量,静态变量等就属于此类存储方式。  

静态存储区:
一定会存在的而且会永恒存在、不会消失,这样的数据包括常量、常变量(const 变量)、静态变量、全局变量等。
静态 、常量、全局变量就是存放在静态存储区,他们在程序编译完成后就已经分配好了,生命周期持续至程序结束。
-----------------------------------------------------------------------------------------------------------------
一、预备知识—程序的内存分配  
  一个由C/C++编译的程序占用的内存分为以下几个部分  
        1、栈区(stack):由编译器自动分配释放   ,存放函数的参数值,局部变量的值等。其  操作方式类似于数据结构中的栈。  
        2、堆区(heap) :一般由程序员分配释放,   若程序员不释放,程序结束时可能由OS回收。注意它与数据结构中的堆是两回事,分配方式倒是类似于链表,呵呵。  
        3、全局区(静态区)(static):全局变量和静态变量的存储是放在一块的,初始化的全局变量和静态变量在一块区域,   未初始化的全局变量和未初始化的静态变量在相邻的另一块区域。程序结束后由系统释放。  
         4、文字常量区:常量字符串就是放在这里的程序结束后由系统释放  

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

-----------------------------------------------------------------------------------------------------------------

总结
从以上分析可知, 静态存储变量是一直存在的, 而动态存储变量则时而存在时而消失。我们又把这种由于变量存储方式不同而产生的特性称变量的生存期。 

生存期表示了变量存在的时间。 生存期和作用域是从时间和空间这两个不同的角度来描述变量的特性,这两者既有联系,又有区别。 一个变量究竟属于哪一种存储方式, 并不能仅从其作用域来判断,还应有明确的存储类型说明。

内存中用户存储空间的分配情况(三种):
程序区:存放程序语句

静态存储区:全局变量,局部静态变量

存放全局变量,在程序开始执行时给全局变量分配存储区,程序执行完毕就释放。

动态存储区:函数形参变量(在调用函数时给形参分配存储空间),局部动态变量(auto register),函数调用现场保护和返回地址等。

-----------------------------------------------------------------------------------------------------------------
二.堆和栈的区别
1.申请方式

(1)栈(satck):由系统自动分配。


  1)程序运行时由编译器自动分配的一块连续的内容,存放函数的参数值,局部变量的值等。
例如,声明在函数中一个局部变量int b;系统自动在栈中为b开辟空间。
  2)程序结束时由编译器自动释放

  3) 栈由系统自动分配,程序员无法控制

  4)只要栈的剩余空间大于所申请空间,系统将为程序提供内存,否则将报异常提示栈溢出。
  5)存取方式,先进后出

(2)堆(heap):

      1)在内存开辟另一块不连续的存储区域。一般由程序员分配释放,
  2)若程序员不释放,程序结束时由系统回收
  3)首先应该知道操作系统有一个记录空闲内存地址的链表,当系统收到程序的申请时,会遍历该链表,寻找第一个空间大于所申请空间的堆结点,然后将该结点从空闲结点链表中删除,并将该结点的空间分配给程序。

       需程序员自己申请(调用malloc,realloc,calloc),并指明大小,并由程序员进行释放。容易产生memory leak.eg:


  
  1. char p;

  2. p = (char *)malloc(sizeof(char));

但是,p本身是在栈中。

----------------------------------------

在c中malloc函数 

如p1 = (char *)malloc(10); 
在C++中用new运算符 
如p2 = (char *)malloc(10); 
但是注意p1、p2本身是在栈中的。 

2.申请大小的限制

        (1)栈:在windows下栈是向底地址扩展的数据结构,是一块连续的内存区域(它的生长方向与内存的生长方向相反)。这句话的意思是栈顶的地址和栈的最大容量是系统预先规定好的,在 WINDOWS下,栈的大小是2M(也有的说是1M,总之是一个编译时就确定的常数)。

栈的大小是固定的。如果申请的空间超过栈的剩余空间时,将提示overflow。因此,能从栈获得的空间较小。

         (2)堆:堆是高地址扩展的数据结构(它的生长方向与内存的生长方向相同),是不连续的内存区域。这是由于系统使用链表来存储空闲内存地址的,自然是不连续的,而链表的遍历方向是由底地址向高地址。堆的大小受限于计算机系统中有效的虚拟内存。由此可见,堆获得的空间比较灵活,也比较大。
3.系统响应:
          (1)栈:只要栈的空间大于所申请空间,系统将为程序提供内存,否则将报异常提示栈溢出。
         (2)堆:首先应该知道操作系统有一个记录空闲内存地址的链表,但系统收到程序的申请时,会遍历该链表,寻找第一个空间大于所申请空间的堆结点,然后将该结点从空闲链表中删除,并将该结点的空间分配给程序,另外,对于大多数系统,会在这块内存空间中的首地址处记录本次分配的大小,这样,代码中的free语句才能正确的释放本内存空间。另外,找到的堆结点的大小不一定正好等于申请的大小,系统会自动的将多余的那部分重新放入空闲链表中。

           说明:

(1)对于堆来讲,频繁的new/delete势必会造成内存空间的不连续,从而造成大量的碎片,使程序效率降低。

(2)对于栈来讲,则不会存在这个问题,

4.申请效率的比较
      (1)栈由系统自动分配,速度快。但程序员是无法控制的

      (2)堆是由malloc分配的内存,一般速度比较慢,而且容易产生碎片,不过用起来最方便。

另外,在WINDOWS下,最好的方式是用VirtualAlloc分配内存,他不是在堆,也不是在栈,是直接在进程的地址空间中保留一块内存,虽然用起来最不方便。但是速度快,也最灵活。

5.堆和栈中的存储内容
        (1)栈:在函数调用时,第一个进栈的主函数中后的下一条语句的地址,然后是函数的各个参数,参数是从右往左入栈的,然后是函数中的局部变量。注:静态变量是不入栈的。当本次函数调用结束后,局部变量先出栈,然后是参数,最后栈顶指针指向最开始存的地址,也就是主函数中的下一条指令,程序由该点继续执行。
         (2)堆:一般是在堆的头部用一个字节存放堆的大小。堆中的具体内容有程序员安排。

6.存取效率的比较

        (1)堆:char *s1=”hellow tigerjibo”;hellow tigerjibo是在编译是就确定的。

        (2)栈:char s1[]=”hellow tigerjibo”;hellow tigerjibo是在运行时赋值的;

用数组比用指针速度更快一些,指针在底层汇编中需要用edx寄存器中转一下,而数组在栈上读取。

栈在读取时直接就把字符串中的元素读到寄存器cl中,而堆则要先把指针值读到edx中,在根据edx读取字符,显然慢了。

补充:

       栈是机器系统提供的数据结构,计算机会在底层对栈提供支持:分配专门的寄存器存放栈的地址,压栈出栈都有专门的指令执行,这就决定了栈的效率比较高。

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

7.分配方式:
(1)堆都是动态分配的,没有静态分配的堆。

(2)栈有两种分配方式:静态分配和动态分配。静态分配是编译器完成的,比如局部变量的分配。动态分配由alloca函数进行分配,但是栈的动态分配和堆是不同的。它的动态分配是由编译器进行释放,无需手工实现。

------------------------------------------------------------------------------------------------------------------

堆和栈的区别可以用如下的比喻来看出: 
使用栈就象我们去饭馆里吃饭,只管点菜(发出申请)、付钱、和吃(使用),吃饱了就走,不必理会切菜、洗菜等准备工作和洗碗、刷锅等扫尾工作,他的好处是快捷,但是自由度小。 

使用堆就象是自己动手做喜欢吃的菜肴,比较麻烦,但是比较符合自己的口味,而且自由度大。

------------------------------------------------------------------------------------------------------------------

堆和栈的区别主要分: 
操作系统方面的堆和栈,如上面说的那些,不多说了。 
还有就是数据结构方面的堆和栈,这些都是不同的概念。这里的堆实际上指的就是(满足堆性质的)优先队列的一种数据结构,第1个元素有最高的优先权;栈实际上就是满足先进后出的性质的数学或数据结构。虽然堆栈,堆栈的说法是连起来叫,但是他们还是有很大区别的,连着叫只是由于历史的原因。  

 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

动态存储区、静态存储区、堆和栈的区别 的相关文章

  • Gazebo教程(使用roslaunch 启动Gazebo,world以及urdf模型)

    Gazebo教程 xff08 使用roslaunch 启动Gazebo xff0c world以及urdf模型 xff09 关于如何学习ROS可以参考古月居的这篇文章 1 https www zhihu com question 35788
  • dispatch_queue_create---创建队列

    dispatch queue create span class hljs keyword const span span class hljs keyword char span label dispatch queue attr t a
  • Java多种方式解决生产者消费者问题(十分详细)

    一 问题描述 生产者消费者问题 xff08 Producer consumer problem xff09 xff0c 也称有限缓冲问题 xff08 Bounded buffer problem xff09 xff0c 是一个多线程同步问题
  • Http协议WWW-Authenticate

    HTTP协议有一个叫WWW Authenticate的头字段 xff0c 可以用于实现登录验证 它是在RFC 2617中定义的 当服务器接收到一个request xff0c 并在实现下面的代码 xff1a br http response
  • Android 运行时注解

    编译时注解点击此处 xff5e xff5e xff5e 运行时注解 以 64 BindView 为例 下面是实现步骤 新建一个 apt annotation 的 java library xff0c 然后在库中新建一个注解 xff0c 传入
  • 使用k-近邻算法识别手写数字。

    在之前的文章中介绍了k 近邻算法的原理知识并且用Python实现了一个分类器 xff0c 而且完成了一个简单的优化约会网站配对效果的实例 在 机器学习实战 中有关kNN的后一部分内容就是一个手写识别系统 xff0c 可以识别手写的0 9的数
  • 在Ubuntu14.04不能添加PPA源到apt源的问题解决方法

    在Ubuntu14 04使用apt get 更新Git 时 xff0c 需要更新apt源 xff0c 添加一个带有最新Git的源 xff0c 如下命令 xff1a sudo add apt repository ppa git core p
  • 单片机的操作本质【以STM32系列为例】

    单片机的操作本质 摘要寄存器的本质单片机的操作本质操作寄存器的方法 摘要 本文档是笔者学习野火F103视频 课时5 至 课时7 的总结 视频链接 xff1a https study 163 com course introduction 1
  • 《视觉SLAM进阶:从零开始手写VIO》第一讲作业

    目录 1 视觉与IMU融合之后有何优势 xff1f 2 有哪些常见的视觉 43 IMU融合方案 xff1f 有没有工业界应用的例子 xff1f 3 在学术界 xff0c VIO研究有哪些新进展 xff1f 有没有将学习方法应用到VIO的例子
  • GPS坐标与UTM坐标的转换

    1 简介 1 1 消息 gps common定义了两个通用消息 xff0c 供GPS驱动程序输出 xff1a gps common GPSFix和gps common GPSStatus 在大多数情况下 xff0c 这些消息应同时发布 xf
  • NVIDIA Jetson TX2使用笔记(一):开机设置

    0 写在前面 由于项目需要 xff0c 使用 NVIDIA Jetson TX2作为硬件开发平台 xff0c 在此记录使用方法和遇到的问题 NVIDIA Jetson TX2是英伟达的嵌入式开发套件 xff0c 可以进行视觉计算 xff0c
  • ORB-SLAM2的安装与运行

    0 背景简介 ORB SLAM是西班牙Zaragoza大学的Raul Mur Artal编写的视觉SLAM系统 他的论文 ORB SLAM a versatile andaccurate monocular SLAM system 34 发
  • Ubuntu14.04升级cmake版本的方法

    在Ubuntu14 04用以下命令默认安装的cmake版本为2 8 x xff0c 有时我们需要更高版本的cmake xff0c 所以需要升级 span class hljs built in sudo span apt get insta
  • 在TX2上配置ORB-SLAM2错误总结

    Pangolin 错误描述 usr lib gcc aarch64 linux gnu 5 aarch64 linux gnu libGL so undefined reference to 96 drmFreeDevice 解决方法 cd
  • docker镜像迁移/移植

    docker镜像迁移 移植 或者docker save 镜像名 版本号 o 路径 保存的包名 tar 通过这两个命令保存保存镜像 xff0c 下载到本地再上传到其他服务器 然后通过docker load lt 保存的包名 tar 完成镜像移
  • 安装并运行VINS-Mono

    0 A Robust and Versatile Monocular Visual Inertial State Estimator VINS Mono是单目视觉惯性系统的实时SLAM框架 它使用基于优化的滑动窗口配方来提供高精度的视觉惯性
  • 使用小觅双目-惯性相机运行VINS-Mono

    步骤 1 下载相机驱动MYNT EYE SDK 2 xff0c 然后make ros xff08 注意 xff1a 前面的Ubuntu安装也要操作 xff09 xff1b 2 安装VINS Mono xff1b 3 在MYNT EYE VI
  • 在TX2上安装VIINS-Mono——问题总结

    1 ceres solver 我们一般通过以下命令安装Eigen xff1a sudo apt get install libeigen3 dev 默认安装在 usr include eigen3 在CMakeList txt中一般用以下语
  • LeGO-LOAM初探:原理,安装和测试

    前言 最近要搞3D激光SLAM xff0c 先后测试了Autoware xff0c cartographer xff0c loam和LeGO LOAM 今天就带来LeGO LOAM的使用体验 Github xff1a https githu
  • IMU噪声标定——加速度计和陀螺仪的白噪声和零偏不稳定性

    前言 imu utils是一个用于分析IMU性能的ROS工具包 参考资料 Allan Variance Noise Analysis for Gyroscopesvectornav gyroscopeAn introduction to i

随机推荐

  • TF坐标变换

    文章目录 TF坐标变换TF功能包TF工具乌龟例程中的TF创建TF广播器创建TF监听器实现乌龟跟随运动 存在的问题总结参考 TF坐标变换 坐标变换是机器人学中一个非常基础 xff0c 同时也是非常重要的概念 机器人本体和机器人的工作环境中往往
  • Linux下目录文件的操作(opendir,readdir,closedir) 以及DIR,dirent,stat等结构体详解

    From http blog chinaunix net uid 27213819 id 3810699 html 注 xff1a 为什么要说 目录文件 xff1f 其实在linux中 目录也是一种 文件 xff0c 只是它的内容是上级的
  • 堆栈的工作原理

    声明 xff1a 以下均为个人收集的一些资料 xff0c 非原创 每一个使用c语言的都应该知道栈的重要性 xff0c 我们能够使用C C 43 43 语言写出诸多复杂的程序 xff0c 很大功劳一部分有归于栈的实现 xff0c 因为它可以帮
  • RTK+GPS提高定位精度原理解析(一个小白写给另一个小白系列)

    RTK 43 GPS提高定位精度原理解析 xff08 一个小白写给另一个小白系列 xff09 GPS定位原理回顾RTK基本概念RTK组成RTK传输差分示意RTK数据链接坐标转换RTK应用后记 我们在上一篇文章导航定位系统的原理解析 xff0
  • Python 嵌套函数中内部函数引用外部函数循环变量情况

    Python 嵌套函数中内部函数引用外部函数循环变量情况 Python中的嵌套函数也称为闭包 xff08 Closure xff09 有一个特点就是内部函数可以引用外部函数内的变量并且在外部函数返回后保存该引用变量的值 xff1b 但是如果
  • Git查看版本改动—— git diff

    HEAD 表示当前版本 xff0c 也就是最新的提交 上一个版本就是 HEAD xff0c 上上一个版本就是 HEAD xff0c 往上100个版本写100个 比较容易数不过来 xff0c 所以写成 HEAD 100 HEAD 2 相当于
  • PyQt5编程-鼠标事件

    处理鼠标事件的频率不低于键盘事件 包括按下 松开鼠标按键 xff1b 移动鼠标到特定区域或离开特定区域 xff1b 更改鼠标指针的形状 xff0c 等等 1 按下 松开鼠标按键 按下并释放鼠标按钮时 xff0c 将调用以下方法 xff1a
  • latex 正文设置为双栏,图片如何占两栏

    xff08 1 xff09 插入一栏图片时 xff0c 使用的是 xff1a begin figure end figure 96 xff08 2 xff09 插入双栏图片时 xff0c 需在figure的上标中加入星号 begin fig
  • VIO松耦合和紧耦合对比

    松耦合 xff08 结果级融合 xff09 xff1a 两个独立的运动估计过程中分别处理视觉和惯性测量的信息 xff0c 最终将他们的输出 xff08 位置和姿态 xff09 融合作为结果 紧耦合 xff08 特征级融合 xff09 xff
  • zed2相机运行VINS-mono

    zed2相机标定请参考专栏前面博文 xff01 一 zed2相机运行VINS mono 1 下载VINS mono mkdir p vins ws src cd vins ws src git clone https github com
  • C语言指针笔试题

    1 我们先来看第一段代码和它的输出 span class token keyword int span span class token function main span span class token punctuation spa
  • Gazebo 官网教程学习笔记--Model Editor

    终端打开Gazebo Gui 界面 然后快捷键CTRL 43 M 打开 Model Editor xff0c 或者在edit 下选择model editor 界面如下 1 工具栏 包含用于编辑模型的工具 2 调色板 也称为左面板 有两个选项
  • 《大厂算法面试》小书

    算法面试是大多数小伙伴的弱势 xff0c 但是大厂几乎都会考算法 xff0c 如果在面试过程中不刻意准备一下算法 xff0c 很大概率被挂 其实对于前端和移动端来说 xff0c 算法要求的并不是很高 xff0c 只要把一些常见的算法题刷完
  • ROS通信架构上——Topic和Msg

    Topic 异步通信方式 Node间通过publish subscribe机制通信 相关的命令 xff1a rostopic rostopic list 列出当前所有topicrostopic info topic name 显示某个top
  • Type-C显示器是什么,Type-C显示器的5大优势

    在显示器领域内 xff0c USB Type C接口还处于发展阶段 xff0c 目前已经在新推出的一些高端显示器和旗舰显示器中有配置 USB Type C接口的出现 xff0c 将会形成以显示器为核心的桌面解决方案 xff0c 用户可以把任
  • SLAM综述

    SLAM综述 前言一 概述二 Lidar SLAM激光雷达传感器激光雷达SLAM系统 xff08 Lidar SLAM System xff09 2D SLAM3D SLAM深度学习与激光雷达Feature amp Detection xf
  • VisionPro使用 C# 开发

    VisionPro 常用控件的说明 工具设置窗体 CogPMAlignEditV2 模版匹配设置窗体控件 CogPMAlignEditV2 Subject 工具关联对象 如 xff1a CogPMAlignEditV2 Subject 61
  • rosdep update 失败及解决办法

    一 问题 reading in sources list data from etc ros rosdep sources list d Hit https raw githubusercontent com ros rosdistro m
  • 在STM32上运行ROS节点——rosserial&stm32开发及调试方法

    近期接手了一些ROS机器人项目 xff0c 这里将开发中遇到的问题和解决方法记录下来 stm32强大的外设资源为机器人底层设备控制带来了极大的便利 xff0c 本文简述借助rosserial项目在stm32中运行ROS节点的方法 基本原理
  • 动态存储区、静态存储区、堆和栈的区别

    C c 43 43 程序经过编译连接后形成的二进制映像文件 xff0c 这文件包含 xff1a 栈 xff0c 堆 xff0c 数据段 xff08 只读数据段 xff0c 已经初始化读写数据段 xff0c 未初始化数据段即BBS xff09