程序运行时对应的内存分布(BSS段、数据段、代码段、堆、栈)关系

参考:程序运行时对应的内存分布关系
作者:嵌入式基地(公众号)
发布时间: 2021-04-28
网址:https://mp.weixin.qq.com/s/AVDPZawSjg9HtxEm8vsFBA

参考:静态变量与动态变量的定义与区别
作者:JoannaJuanCV
发布时间: 2019-01-23 13:14:33
网址:https://blog.csdn.net/zfjBIT/article/details/86608393?spm=1001.2014.3001.5502

内存相关博文:
1、内存四区(代码区 静态区 栈区 堆区)
2、程序运行时对应的内存分布(BSS段、数据段、代码段、堆、栈)关系
3、深入理解STM32内存管理

目录

  • 前言
    • 全局变量初始化
    • 局部变量(栈的引入)
  • 内存分区介绍
    • 程序运行时的内存分区主要分为BSS段、数据段、代码段、堆、栈
    • 静态内存
    • 动态内存
    • 静态变量和动态变量
  • 代码测试
  • 简单说明

前言

以下是韦东山老师讲解笔记: https://www.bilibili.com/video/BV1VM4y137Pm?p=14&spm_id_from=pageDriver

全局变量初始化

在这里插入图片描述
注:全局变量全部copy到RAM,也就是重定位。

在这里插入图片描述

在这里插入图片描述

局部变量(栈的引入)

main()函数里面的局部变量在栈里面

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

之前全局变量是整段复制,局部变量没有那么高的效率,是一个一个执行汇编指令写入到栈里面

在这里插入图片描述

内存分区介绍

程序运行时的内存分区主要分为BSS段、数据段、代码段、堆、栈

  • BSS段:Block Started by Symbol,一般是指存放程序中未初始化的全局变量的一块内存区域。BSS段属于静态内存(下面有介绍,韦东山老师称之为ZI段)分配。

  • 数据段:data segment,一般是指用来存放程序中已初始化的全局变量的一块内存区域。数据段属于静态内存分配。

  • 代码段:code segment/text segment,通常是指用来存放程序执行代码的一块内存区域。这部分区域的大小在程序运行前就已经确定,并且内存区域通常属于只读,某些架构也允许代码段为可写,即允许修改程序。在代码段中,也有可能包含一些 只读的常数变量 ,例如字符串常量等。程序段为程序代码在内存中的映射。一个程序可以在内存中有多个副本。

  • 堆:heap,堆是用于存放进程运行中被动态分配的内存段,它的大小并不固定,可动态扩张或缩减。当进程调用malloc/free等函数分配内存时,新分配的内存就被动态添加到堆上(堆被扩张)/释放的内存从堆中被剔除(堆被缩减)。

  • 栈:stack,栈又称堆栈,存放程序的局部变量(但不包括static声明的变量, static 意味着在数据段中 存放变量)。除此以外,在函数被调用时,栈用来传递参数和返回值。

静态内存

静态内存是由系统自动分配内存,由系统自动释放。静态内存是在栈中分配的,假如main函数调用另一个函数,那么就把被调用函数压到一个栈里面。执行这个被调函数就是使系统为这个函数分配的所有内存空间逐个出栈。出栈全部结束就是被调用函数执行完毕。

出栈的顺序是先进后出,也就是先进栈的后执行(前面介绍的print输出例子),因为先进栈被压在下面,所以执行的永远是栈顶的内容。程序执行完毕的意思就是“栈里面所有的内容全部都出栈了”。出栈就是“释放”。栈顶全部出栈后原来位于栈顶就会成为栈顶,然后继续执行该栈定内容,继续出栈。整个程序全部执行完毕的意思就是“系统所分配的内存空间全部出栈”,内存全部释放完毕。所以系统为静态变量分配的内存空间在程序中执行完毕后都会被释放。

动态内存

动态内存是由程序员手动释放,函数终止不会被系统自动释放。这说明他肯定不是在栈里面分配的。那他是在什么地方分配的呢?是在“堆中”分配的,栈是一种存储结构,堆不是一种存储结构,堆是分配内存的一种排序方式。也就是说,动态内存是以堆排序的方式分配的。以前讲排序,如冒泡排序,插入排序,选择排序,快速排序。堆排序也是一种排序方式,因为动态内存是在堆中分配的,是以排序的方式分配的,不是在栈中,所以函数运行结束后也不会被释放。

也因为动态内存是由程序员手动分配,手动释放,所以这时候就会有一个比较严重的问题:如果忘记释放了,就会导致内存泄露,所以动态分配内存有优点,也有缺点。动态内存的使用非常灵活,但需要注意的问题也很多。

静态变量和动态变量

1.定义上,静态变量比动态变量在多一个关键字static,比如:

动态变量::int i;

静态变量:static int i;

2.动态变量在子程序中,每次调用都会从它的初始值开始调用,而不管他在函数中经历了什么变化;静态变量会从变化后的值继续改变。

void fun()        
{int j=0;j++;printf("%d",j);
}void fun1()        
{static int j=0;j++;printf("%d",j);
}void main()
{int i;for(i=0;i<5;i++)fun();//输出结果为11111printf("\n");for(i=0;i<5;i++)fun1();//输出结果为12345
}

程序中内存分布图
在这里插入图片描述

APUE中的C内存分布图
在这里插入图片描述

代码测试

#include <stdio.h>
#include <stdlib.h>int g1=0, g2=0, g3=0;static int max(int i) {int m1 = 0, m2 , m3 = 0, *p_max;static n1_max = 0, n2_max , n3_max = 0;p_max = (int*)malloc(10);printf("打印max程序地址\n");printf("in max: %p\n\n",max);printf("打印max传入参数地址\n");printf("in max: %p\n\n",&i);printf("打印max函数中静态变量地址\n");printf("%p\n",&n1_max); < 打印各本地变量的内存地址printf("%p\n",&n2_max);printf("%p\n\n",&n3_max);printf("打印max函数中局部变量地址\n");printf("%p\n",&m1);     < 打印各本地变量的内存地址printf("%p\n",&m2);printf("%p\n\n",&m3);printf("打印max函数中malloc分配地址\n");printf("%p\n\n",p_max); < 打印各本地变量的内存地址if(i) {return 1;} else {return 0;}}int main(int argc, char **argv) {static int s1 = 0, s2, s3 = 0;int v1 = 0, v2, v3 = 0;int *p;   p = (int*)malloc(10);printf("打印各全局变量(已初始化)的内存地址\n");printf("%p\n",&g1); < 打印各全局变量的内存地址printf("%p\n",&g2);printf("%p\n\n",&g3);printf("======================\n");printf("打印程序初始程序main地址\n");printf("main: %p\n\n", main);printf("打印主参地址\n");printf("argv: %p\n\n",argv);printf("打印各静态变量的内存地址\n");printf("%p\n",&s1); < 打印各静态变量的内存地址printf("%p\n",&s2);printf("%p\n\n",&s3);printf("打印各局部变量的内存地址\n");printf("%p\n",&v1); < 打印各本地变量的内存地址printf("%p\n",&v2);printf("%p\n\n",&v3);printf("打印malloc分配的堆地址\n");printf("malloc: %p\n\n",p);printf("======================\n");max(v1);printf("======================\n");printf("打印子函数起始地址\n");printf("max: %p\n\n",max);system("pause");return 0;}

根据输出结果可以看出,传入的参数,局部变量,都是在栈顶分布,随着子函数的增多而向下增长。函数的调用地址(函数运行代码),全局变量,静态变量都是在分配内存的低部存在,而malloc分配的堆则存在于这些内存之上,并向上生长。

打印各全局变量(已初始化)的内存地址
00405008
0040500C
00405010======================
打印程序初始程序main地址
main: 00401457打印主参地址
argv: 00DE15C8打印各静态变量的内存地址
00405014
00405018
0040501C打印各局部变量的内存地址
0060FEF8
0060FEF4
0060FEF0打印malloc分配的堆地址
malloc: 00DE15D8======================
打印max程序地址
in max: 00401334打印max传入参数地址
in max: 0060FEE0打印max函数中静态变量地址
00405020
00405024
00405028打印max函数中局部变量地址
0060FEC8
0060FEC4
0060FEC0打印max函数中malloc分配地址
00DE3E38======================
打印子函数起始地址
max: 00401334请按任意键继续. . .

简单说明

在这里插入图片描述

左边的是UNIX/LINUX系统的执行文件,右边是对应进程逻辑地址空间的划分情况。

首先是堆栈区(stack),堆栈是由编译器自动分配释放,存放函数的参数值,局部变量的值等。其操作方式类似于数据结构中的栈。栈的申请是由系统自动分配,如在函数内部申请一个局部变量 int h,同时判别所申请空间是否小于栈的剩余空间,如若小于的话,在堆栈中为其开辟空间,为程序提供内存,否则将报异常提示栈溢出。

其次是堆(heap),堆一般由程序员分配释放,若程序员不释放,程序结束时可能由OS回收。注意它与数据结构中的堆是两回事,分配方式倒是类似于链表。堆的申请是由程序员自己来操作的,在C中使用malloc函数,而C++中使用new运算符,但是堆的申请过程比较复杂:当系统收到程序的申请时,会遍历记录空闲内存地址的链表,以求寻找第一个空间大于所申请空间的堆结点,然后将该结点从空闲结点链表中删除,并将该结点的空间分配给程序,此处应该注意的是有些情况下,新申请的内存块的首地址记录本次分配的内存块大小,这样在delete尤其是 delete[]时就能正确的释放内存空间。

接着是全局数据区(静态区) (static),全局变量和静态变量的存储是放在一块的,初始化的全局变量和静态变量在一块区域,未初始化的全局变量和未初始化的静态变量在相邻的另一块区域。另外文字常量区,常量字符串就是放在这里,程序结束后有系统释放。

最后是程序代码区,放着函数体的二进制代码。

内存分布对应关系

在这里插入图片描述

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

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

相关文章

java线程池 锁_java多线程——锁

这是多线程系列第四篇&#xff0c;其他请关注以下&#xff1a;如果你看过前面几篇关于线程的文字&#xff0c;会对线程的实现原理了然于胸&#xff0c;有了理论的支持会对实践有更好的指导&#xff0c;那么本篇会偏重于线程的实践&#xff0c;对线程的几种应用做个简要的介绍。…

Ubuntu时间显示不准确的解决方案

参考&#xff1a;解决ubuntu里面时间不正确的办法 作者&#xff1a;三速何时sub20 发布时间&#xff1a;2020-12-08 16:24:27 网址&#xff1a;https://blog.csdn.net/weixin_44234294/article/details/110875899?spm1001.2014.3001.5501 目录1、进入终端2、输入命令3、选择 A…

Ubuntu下软件的安装、卸载方法

参考&#xff1a;Ubuntu 如何使用命令卸载安装过的软件&#xff08;超级简单&#xff09; 作者&#xff1a;一只青木呀 发布时间&#xff1a;2020-08-04 09:19:01 网址&#xff1a;https://blog.csdn.net/weixin_45309916/article/details/107778981 参考&#xff1a;Ubuntu下软…

Ubuntu文件压缩、解压缩、打包解包(带软链接)、拷贝文件(带软链接)、拷贝文件夹

参考&#xff1a;Ubuntu 命令解压文件大全 作者&#xff1a;一只青木呀 发布时间&#xff1a; 2020-08-04 17:18:55 网址&#xff1a;https://blog.csdn.net/weixin_45309916/article/details/107791294 参考&#xff1a;打包和压缩的概念和区别 作者&#xff1a;不浪漫的罪名L…

Ubuntu开启FTP服务方法(Ubuntu和Windows之间互传文件需要开启——服务器端)

目录Ubuntu开启FTP服务步骤&#xff1a;Ubuntu开启FTP服务步骤&#xff1a; 工作中Ubuntu和Windows之间互传文件&#xff0c;需要服务器端&#xff08;Ubuntu&#xff09;开启FTP服务&#xff0c;客户端&#xff08;Windows&#xff09;安装FileZilla。平时自己学习电脑安装虚拟…

win7共享wifi

为什么80%的码农都做不了架构师&#xff1f;>>> 1.从开始菜单找到“命令提示符”&#xff0c;或直接键入cmd快速搜索&#xff0c;右键单击它&#xff0c;选择“以管理员身份运行” 2.运行以下命令启用虚拟无线网卡&#xff1a; netsh wlan set hostednetwork mod…

Ubuntu开启NFS、SSH服务(驱动开发用到、电脑端登录ARM板用到)

参考&#xff1a;Ubuntu下NFS服务的开启 作者&#xff1a;一只青木呀 发布时间&#xff1a;2020-08-04 14:06:58 网址&#xff1a;https://blog.csdn.net/weixin_45309916/article/details/107784877 目录NFS服务的开启1.安装NFS服务2.创建 linux 工作目录3.配置NFSUbuntu下SSH…

【整理】MySQL 之 autocommit

2019独角兽企业重金招聘Python工程师标准>>> mysql 默认是开启 auto commit 的。可以通过如下命令查看 session 级别和 global 级别的设置&#xff1a; mysql> select session.autocommit; ---------------------- | session.autocommit | ---------------------…

交叉编译链的安装

参考&#xff1a;嵌入式 交叉编译链的安装 作者&#xff1a;一只青木呀 发布时间&#xff1a;2020-08-04 18:13:13 网址&#xff1a;https://blog.csdn.net/weixin_45309916/article/details/107789879 目录什么是交叉编译器交叉编译器的下载交叉编译器的安装1.把下载的文件放到…

Ubuntu下安装VS Code以及C/C++插件(PS工作目录的创建)

参考&#xff1a;Visual Studio Code Ubuntu下安装 以及C/C插件大全 作者&#xff1a;一只青木呀 发布时间&#xff1a;2020-08-05 11:55:53 网址&#xff1a;https://blog.csdn.net/weixin_45309916/article/details/107811506 目录为何选择安装VS CodeVisual Studio Code 安装…

Common Lisp中调用R

2019独角兽企业重金招聘Python工程师标准>>> R是功能强大的统计软件&#xff0c;和Lisp一样也有一个交互式的命令行环境&#xff0c;还有众多的扩展库&#xff0c;可以用来进行专业的统计分析。要在Common Lisp中方便的调用R的功能&#xff0c;可以试用rcl这个库。安…

java生成pdf加密_java使用iText 生成PDF全攻略(表格,加密)

java使用iText 生成PDF全攻略,包括创建文档,设置字体,添加表格(PdfPTable),创建新页(newPage),设置布局,加密主要使用的jar包: itextpdf-5.4.2.jar,itext-pdfa-5.4.2.jar,itext-xtra-5.4.2.jar,如果用到中文&#xff0c;需要CJK字体的扩展包&#xff1a;itext-asian.jar如果用到…

恩智浦NXP I.MX6ULL芯片介绍下载官网资料

参考&#xff1a;NXP I.MX6ULL芯片介绍以及资料的获取 作者&#xff1a;一只青木呀 发布时间&#xff1a;2020-09-26 10:54:26 网址&#xff1a;https://blog.csdn.net/weixin_45309916/article/details/108808573 目录I.MX6ULL芯片介绍以及官网资料的获取I.MX6ULL芯片介绍以及…

判定点是否在不规则多边形内部的问题

2019独角兽企业重金招聘Python工程师标准>>> 问题如下&#xff1a; 话说在平面内有一个任意的不规则的封闭多边形&#xff0c;另外在这个平面内还有一个点&#xff0c;问题&#xff1a;如何高效的判定这个点是在这个多边形内部还是外部&#xff1f;补充&#xff1a…

Cortex-A7 MPCore 架构详细介绍(九种运行模式、内核寄存器组R0~R15,有特定的名字和功能)

目录0.ARM架构的历史简介1.Cortex-A7 MPCore(即多核) 简介2.Cortex-A 处理器九种运行模式3.Cortex-A 寄存器组&#xff08;内核寄存器&#xff09;3.1通用寄存器3.1.1未备份寄存器(R0~R7)3.1.2备份寄存器(R8~R12、SP指针R13、备份R14也叫LR)3.1.3程序计数器R15(PC)3.2程序状态寄…

Java开发中遇到具有挑战的事_Java并发编程的挑战:遇到的问题及如何解决

并发编程的目的是为了让程序运行得更快&#xff0c;但是&#xff0c;并不是启动更多的线程就能让程序最大限度地并发执行。在进行并发编程时&#xff0c;如果希望通过多线程执行任务让程序运行得更快&#xff0c;会面临非常多的挑战&#xff0c;比如上下文切换的问题、死锁的问…

树莓派(TCP客户端 )和Wemos(TCP服务端连接红外模块)通讯实现对红外设备的控制

参考&#xff1a;U如何用树莓派连接语音模块&#xff0c;红外模块来控制红外设备详解 作者&#xff1a;一只青木呀 发布时间&#xff1a;2020-08-12 17:14:10 网址&#xff1a;https://blog.csdn.net/weixin_45309916/article/details/107960066 目录硬件软件红外解码步骤1.连接…

java反编译微信小程序_教你如何一键反编译获取任何微信小程序源代码(图形化界面,傻瓜式操作)...

一键获取微信小程序源代码1 Tips&#xff1a;2   一键获取微信小程序源码, 使用了C#加nodejs制作 直接解压在D盘根目录下后就可以使用 将小程序文件放到 wxapkg目录下3 这个目录下有一些demo 可以先进行实验 使用正确 wxapkg exe这些文件应该在 D:CrackMinApp目录下4 然后打开…

PM2管理工具的使用

linux上PM2可以管理服务程序&#xff0c;防止程序无故关闭&#xff0c;具有程序守护功能&#xff0c;自动重启服务器程序&#xff0c;监控程序等好处&#xff0c;很方便&#xff0c;具体自己去体会! 官网地址&#xff1a; http://pm2.keymetrics.io/ 文档指南&#xff1a; ht…

C语言常用字符串操作函数大全详解(strstr,strtok,strrchr,strcat,strcmp,strcpy,strerror,strspn,strchr等)

参考&#xff1a;string.h中常用字符串操作函数说明&#xff08;strstr&#xff0c;strtok&#xff0c;strrchr&#xff0c;strcat&#xff0c;strcmp&#xff0c;strcpy&#xff0c;strerror&#xff0c;strspn&#xff0c;strchr等&#xff09; 作者&#xff1a;一只青木呀 发…