程序运行时对应的内存分布(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,一经查实,立即删除!

相关文章

JS数字转中文

function number2Chinese(n) {if (!/^(0|[1-9]\d*)(\.\d)?$/.test(n)) return 数据非法;let unit 京亿万仟佰拾兆万仟佰拾亿仟佰拾万仟佰拾元角分,str ;n 00;let p n.indexOf(.);if (p > 0) n n.substring(0, p) n.substr(p 1, 2);unit unit.substr(unit.length - …

“捆绑”住用户,需要优秀的产品(经验分享)

捆绑&#xff0c;是一种野蛮的方式。若是主动的去被捆绑&#xff0c;意义反差就大了。用户容易被新奇的东西所吸引&#xff0c;会主动的去了解。若是符合自身需求性&#xff0c;会甘愿的成为其中的一员。这样的现象&#xff0c;是被捆绑体现。正如周鸿祎所言&#xff0c;做出好…

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…

【洛谷P2680】运输计划

题目链接 题目大意&#xff1a; 一棵\(n\)个点的带边权的数&#xff0c;给定\(m\)条树上两点间的路径&#xff0c;现在你可以让树上任意一条边的权值变为零&#xff0c; 问如何选边使得\(m\)条路径中边权和最大的路径的边权和最小 \(\mathcal{solution}\) 这是\(NOIP2015\)的\(…

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下软…

webservice系统学习笔记9-使用契约优先的方式的一个服务端demo(隐式传Header信息)...

服务器端&#xff1a; 1、编写wsdl文件 <?xml version"1.0" encoding"UTF-8" standalone"no"?> <wsdl:definitions xmlns:soap"http://schemas.xmlsoap.org/wsdl/soap/" xmlns:tns"http://www.example.org/mywsdl/&qu…

java gzip 多个文件_Java Zip多文件压缩和 GZIP压缩

/*** 多文件压缩** author Administrator**/public class ZipCompress {public static void main(String args[]) {String[] filepaths { "D:\\zip1.txt", "D:\\zip2.txt" };try {FileOutputStream f new FileOutputStream("D://test.zip");//…

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

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

java 内存和实际内存_请问更改eclipse内存和更改jvm内存是一会事儿吗?

RSS列 表示&#xff0c; 程序占用了多少物理内存。 虚拟内存可以不用考虑&#xff0c;它并不占用实际物理内存。 (2). top 命令也可以 其中VIRT(或VSS)列 表示&#xff0c;程序占用了多少虚拟内存。 同 ps aux 中的 VSZ列 RES列 表示&#xff0c; 程序占用了多少物理内存。同 p…

thinkphp 编辑器kindeditor

首先&#xff0c;去官网下载最新版的kindeditor&#xff0c;然后把里面asp&#xff0c;jsp&#xff0c;net&#xff0c;example的全删除&#xff0c;然后改名为editor放进public&#xff08;最外层目录的public&#xff09;文件夹里面 在目录lib目录建立ORG文件夹&#xff08;个…

equation

equation 题目描述 有一棵n 个点的以 1 为根的树, 以及 n 个整数变量xi。树上 i 的父亲是 fi&#xff0c; 每条边(i,fi)有一个权值wi&#xff0c;表示一个方程 xi xfi wi&#xff0c;这 n-1个方程构成了一个方程组。 现在给出q 个操作&#xff0c;有两种类型: 1 u v s&#x…

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

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

舞伴配对问题java_舞伴配对问题

循环队列的应用——舞伴配对问题&#xff1a;在舞会上&#xff0c;男、女各自排成一队。舞会开始时&#xff0c;依次从男队和女队的队头各出一人配成舞伴。如果两队初始人数不等&#xff0c;则较长的那一队中未配对者等待下一轮舞曲。假设初始男、女人数及性别已经固定&#xf…

逆元

复习逆元…… 逆元 求法&#xff1a; 1&#xff0c;快速幂     根据费马小定理有\(a^{p - 1} \equiv 1 \quad (mod \quad p)\),把左边拆开一下得到     \[a \cdot a^{p - 2} \equiv 1 \quad (mod \quad p)\]     因此\(a^{p - 2}\)为\(a\)在\(mod \quad p\)意义下的…

java如何让线程等待_如何使Java线程等待另一个线程的输出?

我真的建议你经历一个教程&#xff0c;如Sun’s Java Concurrency&#xff0c;你开始在多线程的魔法世界。还有一些好书出来了(google for“Concurrent Programming in Java”&#xff0c;“Java Concurrency in Practice”)。要得到你的答案&#xff1a;在你必须等待dbThread的…

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 | ---------------------…

java某个类避免findbug检查_Findbugs能否在java中检测到捕获RuntimeException?

你能不能让我知道Findbugs可以在java中检测到catcing RuntimeException吗&#xff1f;有效的java建议我们不要捕获RuntimeException.所以我想知道Findbugs可以抓错了.另外,我已经检查过Klocwork JD.CATCH和checkstyle IllegalCatch是否适用于此目的.最佳答案 有点.在findbugs中…