【C语言进阶深度学习记录】三十五 程序中的堆、栈以及静态存储区(数据区)

学习交流加

  • 个人qq:
    1126137994
  • 个人微信:
    liu1126137994
  • 学习交流资源分享qq群:
    962535112

在我之前学习底层的知识的时候,也写过相关的内容。可以对比的学习:【软件开发底层知识修炼】二十 深入理解可执行程序的结构,【软件开发底层知识修炼】二十三 ABI-应用程序二进制接口三之深入理解函数栈帧的形成与摧毁

学习本文的前提是了解进程的内存布局空间。可以看上面两篇博客进行巩固

文章目录

    • 1 程序中的栈内存结构
      • 1.1 函数的调用过程对应的栈的变化
        • 1.11 函数调用栈上的数据
    • 2 程序中(应该称为进程中才对)的堆结构
    • 3 程序中的静态存储区(其实就是数据区)
    • 4 总结

1 程序中的栈内存结构

  • 栈在程序中用于维护函数调用的上下文
  • 函数中的参数和局部非静态变量存储在栈上
  • esp指针始终指向栈顶
  • ebp是函数栈帧,用于定位的,使用ebp可以查找到函数的参数,返回地址等信息。后面的函数调用分析会认识到这一点
  • 栈在整个进程内存空间中是从上往下扩展,也就是从高地址往低地址扩展。如下图是一个栈

在这里插入图片描述

push 操作相当于往栈中填数据,esp指针会向下走。pop操作相当于将栈顶数据弹出,esp指针会网上走。

那么栈对于程序而言,到底有什么用呢?

栈用于保存一个函数调用的时候所需要维护的信息,包括函数的参数、返回地址、局部变量、上下文信息等。它们在栈中的位置大致如下图所示:

在这里插入图片描述

1.1 函数的调用过程对应的栈的变化

每次函数调用都对应一个栈上的活动记录,被调用函数的活动记录位于调用函数的下面。比如有如下的几个函数调用:

在这里插入图片描述

那么在某一个时刻,栈中的内容大致是这样的:

在这里插入图片描述

注意:上面的栈中的内容并没有具体,只是说明各个函数的活动记录信息在哪个文职,具体里面的内容没有列出。看下面的分析:

从程序开始运行时分析:

  1. 从main函数开始运行

当main开始运行的时候,main函数的栈的信息是下面这样的:

在这里插入图片描述

  • 可以看到,首先入栈的是函数参数,然后是函数的返回地址
  • old_ebp代表调用main函数的ebp的位置。这个暂且不管
  • 可以看到,ebp向上偏移4字节(在X86 32位系统中,栈是以4字节为单位进行存储数据,所以一次偏移就是4字节)就能找到返回地址(这个返回地址是调用main函数的那个函数之前执行指令的地址)。ebp向下偏移4字节就是old_ebp。所以说ebp是函数栈帧,用于定位查找其他参数
  • esp始终指向栈顶
  1. 当main函数调用f()函数

当main函数执行到调用f() 函数的时候,main函数的活动记录(寄存器,返回地址等)需要保存入栈,f() 函数的参数信息需要入栈。如下图所示:

在这里插入图片描述
可以看到:

  • f函数的参数先入栈
  • 然后返回地址入栈(main函数调用f()函数那里的地址)
  • 然后main函数的ebp的地址入栈。用于定位上一个函数的ebp
  • 然后才是函数中的局部非静态变量信息入栈。这个参数的入栈顺序可以参考本文开头给出的两篇文章中的内容

f函数调用g函数就是一样的过程,这里就不再赘述。下面直接上当f执行完返回的过程是怎样的?

  1. 当从f()调用中返回到main函数的栈的变化

在这里插入图片描述

上述f返回后当前栈就只有白色空白部分,下面的深颜色(橘黄色???分不清)并不是当前栈的内容了

可以看出;

  • 通过f函数栈帧中的old_ebp找到main函数的ebp,然后将当前ebp寄存器指向它。
  • 通过f栈帧中的返回地址找到main函数之前被中断的地址处,main函数继续执行。关于这里,非常详细的文章请参考:【软件开发底层知识修炼】二十三 ABI-应用程序二进制接口三之深入理解函数栈帧的形成与摧毁

1.11 函数调用栈上的数据

函数调用栈上的数据,在函数返回时,将被释放,不再有效。所以对于以下代码,是错误的代码;

在这里插入图片描述

2 程序中(应该称为进程中才对)的堆结构

  • 堆空间是进程的内存空间中一块预留的内存空间,供程序在运行的时候动态分配。
  • 使用malloc与free进行堆中的内存的动态申请(具体的使用可以参考这篇文章:【C语言进阶深度学习记录】三十三 C语言中动态内存分配

对于堆空间,本文只简单的讲述系统对堆空间的管理方式(也就是使用malloc时,系统是如何申请内存的,以及系统对内存的管理方式,当然本文也是简单描述,具体可以参考CSAPP书籍中相关章节)

操作系统对堆的管理方式主要有:

  • 空闲链表法、位图法、对象池法

下面主要简要说明空闲链表发的原理:

空闲链表就是操作系统将整个可用的堆内存空间分为一块一块的,对应的相同数量的指针指向各个内存块,然后内存块的末尾又是一个指针指向下一个内存块的头。

其实简单来说就是将多个内存块串联成一个链表形式。

如下图所示:

在这里插入图片描述

当使用malloc函数进行内存分配的时候,系统会遍历链表,找到能够满足申请大小的且没有被别人申请的空闲的链表的一个节点对应的内存块。比如上图,申请一个4字节的内存,最终遍历链表找到了一个大小为5字节的内存块,然后系统就为我们在该内存块上申请4字节的内存空间供指针p使用。

简单来说,空闲链表法就是上述的大致过程。

想要深入了解操作系统对堆空间的管理,可以阅读书籍《深入理解计算机系统》(csapp)。本文不再重复赘述。

3 程序中的静态存储区(其实就是数据区)

我们一般说进程,但这里说程序。有些术语描述真的是很模棱两可,但是只要自己明白就行

在进程的地址空间,栈,堆是程序运行时的效果。我们也知道这两个内存对应的数据到底是什么。

那么对于下面程序中的变量g_init_v,g_uninit_v,s_v1,s_v2以及字符串字面量,它们是存储在哪里呢?

在这里插入图片描述

我们已经看到了上图中,它们在可执行文件中都是存储在.data区,.bss区。这些区域。

当程序运行起来之后,它们还是会在进程的内存空间的.data与.bss段。与可执行文件的data与bss名字一样如下图

在这里插入图片描述
我们称之为静态存储区。为什么叫静态?并不是因为static,而是因为它们的值虽然有可能被改变,但是却一直在那个区域。不像栈区域的值最后会被销毁,堆上的值也需要free。

现在终于明白静态存储区实际就是.data与.bss区域了。

下面总结一下静态存储区的几点重要知识:

  1. 静态存储区是随着程序的运行而分配空间
  2. 静态存储区的生命周期直到程序运行而结束
  3. 在程序的编译期间,静态存储区的大小就已经确定
  4. 静态存储区主要用于保存全局变量静态局部变量以及类似于字符串字面量样式的字面量

4 总结

栈,堆与静态存储区是进程地址空间的基本数据区域。

  • 一定要注意区分可执行文件中的内容与程序运行起来后的进程地址空间中的内容的差别。
  • 本文所描述的就是进程地址空间中内容。可执行文件的内容可参考书籍《程序员的自我修养》

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/422775.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【C语言进阶深度学习记录】三十六 程序与进程的区别(程序的内存布局)

上一篇文章学了堆,栈以及静态存储区。它们实际上都是针对进程来说的。那么程序与进程有什么区别呢? 本文不细讲程序与进程。 1 程序与进程 1.1 什么是程序 写完的.c文件是源文件。也叫源代码。 将源代码编译后,会生成可执行文件程序&#…

使用Cucumber+Rspec玩转BDD(2)——邮件激活

使用CucumberRspec玩转BDD(2)——邮件激活 2009年3月2日 星期一 ### 温故知新 ###前面我们已经完成了新用户注册功能的开发,为了方便我们后面的开发工作且不扰乱之前的工作成果,我们先将这份源代码归档并做个标记。为了获得更好的阅读体验,读…

【C语言进阶深度学习记录】三十七 C/C++中造成程序内存错误的原因(野指针)

什么是野指针? 指针变量存的地址是一块非法内存地址。进而形成野指针。但是需要注意一点,野指针不是NULL指针。 文章目录1 野指针的概念1.1 野指针代码案例初探2 如何避免野指针2.1 野指针代码案例分析进阶3 总结1 野指针的概念 野指针变量中的值是非法…

算法补充 2011-9-12

设计一个算法将顺序表L中所有小于0的整数放前半部分&#xff0c;大于等于0的整数放在后半部分二叉树的删除设计一个算法将顺序表L中所有小于0的整数放前半部分&#xff0c;大于等于0的整数放在后半部分 思路:从左侧找出>0的元素&#xff0c;从右侧找出<0的元素,然后进行交…

【C语言进阶深度学习记录】三十八 C/C++语言中的函数声明与函数定义

文章目录1 函数的声明和定义1.1 代码分析2 总结1 函数的声明和定义 声明的意义在于告诉编译器程序单元的存在。只是告诉编译器它存在但是不在声明这里定义&#xff0c;有可能在当前文件中的其他地方或者其他文件中定义。如果在它还没有被定义之前就使用它&#xff0c;会导致编…

ASP.NET MVC3 系列教程 - 部署你的WEB应用到IIS 6.0

I:ASP.NET MVC3 部署的前期工作 1.确认部署的服务器操作系统环境 首先我们确认服务器的操作系统版本可以从系统命令行工具里输入: systeminfo 获取相关操作系统信息例如然后再确认IIS版本信息 -> 打开IIS管理工具即可接着确认.NET Framework的版本可以在系统命令行工具执行:…

【C语言进阶深度学习记录】三十九 C语言中的可变参数(参数可变的函数)

用过printf()函数的热都知道&#xff0c;printf的参数可以有多个&#xff0c;它是可变的&#xff0c;根据我们输出参数的类型以及个数的不同来确定参数。今天来学习C语言中参数可变的函数是如何实现的。 文章目录1 可变参数2 总结1 可变参数 首先我们要明白一点&#xff0c;在…

【离散数学中的数据结构与算法】一 最大公约数与最小公倍数之间的关系

文章目录1 算数基本定理2 最大公约数3 最小公倍数4 性质5 推论1 算数基本定理 设正整数 n>1&#xff0c; 则 n 可唯一地表示为&#xff1a; 其中 p1<p2<,…, <ps 是 s 个相异的素数&#xff0c; 指数ki都是正整数。 此定理又称作唯一析因定理&#xff08;unique f…

【离散数学中的数据结构与算法】二 欧几里得算法与裴蜀等式

欧几里得算法是计算两个数最大公因子算法。又称辗转相除法。本文将学习为什么辗转相除法可以求得两个数的最大公因子。同时也可以根据最大公因子计算两个数的最小公倍数。 文章目录1 欧几里得算法的理论基础1.1 欧几里得算法&#xff08;辗转相除法&#xff09;2 裴蜀等式&…

【离散数学中的数据结构与算法】四 加法法则与乘法法则

文章目录1 加法法则2 乘法法则3 例子3.1 例一3.2 例二3.3 例三4 总结1 加法法则 加法法则&#xff1a; 设事件 A 有 m 种产生方式&#xff0c; 事件 B 有n 种产生方式&#xff0c;则当 A 与 B 产生的方式不重叠时&#xff0c;“事件 A 或 B 之一” 有 mn 种产生方式。 加法法…

前端学习(310):清除浮动的方法

我们经常把高度塌陷问题也叫做常见的几种清除浮动的方法 高度塌陷问题—父元素高度自适应&#xff0c;子元素float后&#xff0c;造成父元素高度为0&#xff0c;就叫做高度塌陷问题 给父元素一个高度 缺点&#xff1a;无法高度自适应 父元素{overflow:hidden;} 缺点&#xf…

【离散数学中的数据结构与算法】五 排列与组合一

在leetcode刷题过程中&#xff0c;遇到过很多关于排列组合的问题。弄清楚排列组合的相关原理&#xff0c;是非常有用处的。 文章目录1 问题2 排列-有序选取2.1 重复选取-可重排列2.2 不重复选取-排列2.21 全排列3 例题4 总结1 问题 设集合S包含n个元素&#xff0c;从S中选取r个…

Google Maps 地址转化成坐标

http请求格式http://maps.google.com/maps/geo?q查询关键字&outputkml(输出格式可以 为xml kml json)&oeutf8&sensortrue或者false&key你的apikey示例http://maps.google.com/maps/geo?q湖南大学软件学院&outputkml&keyabcdefg(api key)输出kml文件如…

【离散数学中的数据结构与算法】六 排列与组合二

接着上一篇学习&#xff1a;【离散数学中的数据结构与算法】五 排列与组合一 上一篇文章主要学习了可重复选取的可重排列和不可重复选取的排列。他们都是在n个不同的对象中选取。 今天我们俩学习的是&#xff0c;当这个n个对象中有相同的元素的时候&#xff0c;排列的相关定理…

【离散数学中的数据结构与算法】七 排列与组合三

前两篇文章学习了不可重复选取的排列与可重复选取的可重排列。本篇文章开始学习组合的相关定理。 文章目录1 组合1.1 组合的计算公式2 总结1 组合 跟排列一样。组合也分为不重复选取的组合&#xff0c;与可重复选取的可重组合。本节内容主要学习不可重复选取的组合 从 n 个不…

Silverlight4.0教程之WebBrowser控件(Silverlight内置HTML浏览器控件)

微软于PDC2009上发布Silverlight 4 Beta版&#xff0c;微软在Silverlight 4版本中处理了约8000个的Silverlight终端用户的请求&#xff0c;加入了一系列另开发人员兴奋的新特性&#xff0c;最突出的主要体现在几个方面&#xff1a; 开发工具增强&#xff1a;Visual Studio 2010…

【离散数学中的数据结构与算法】八 排列与组合四

上一篇文章学习了组合&#xff08;不可重复选取的&#xff09;。今天来将可重复选取的组合学习一下。 文章目录1 可重复选取的组合-可重组合2 总结1 可重复选取的组合-可重组合 现在有4种口味的棒棒糖&#xff0c;你要从中选3个(允许你选同种口味)总共有多少种不同的选法&…