程序人生 | C 语言编译器对内存空间的分配原则

C语言程序编译后内存地址的分配 一、C程序内存分配 各变量分配地址 C语言在内存中一共分为如下几个区域,分别是: 1、栈区(stack) 由编译器自动分配释放,存放函数的参数值,局部变量的值等。其操作方式类似于数据结构中的栈。 2、堆区(heap) 一般由程序员分配释放,若程序员不释放,程序结束时可能由OS回收 。它与数据结构中的堆不同,分配方式类似于链表。 3、全局区(静态区)(static) 全局变量和静态变量的存储是放在一块的,初始化的全局变量和静态变量在一块区域, 未初始化的全局变量、未初始化的静态变量在相邻的另一块区域。当程序结 阅读详情

本文首发于 2015-05-04 14:50:16

概述

一个由 C/C++ 编译的程序占用的内存分为以下几个部分:

  1. 栈区(stack):由编译器自动分配、释放,存放函数的参数值、局部变量的值等,其操作方式类似于数据结构中的栈。一般大家常说的堆栈和栈是一样的,就是栈(stack),而说 堆 时才是堆 heap 。
  2. 堆区(heap):一般由程序员分配释放,若程序员不释放,程序结束时由OS回收。注意它与数据结构中的堆是两回事,分配方式倒是类似于链表。
  3. 全局区(静态区,static):全局变量和静态变量的存储是放在一块的,初始化的全局变量和静态变量在一块区域,未初始化的全局变量和未初始化的静态变量在相邻的另一块区域。程序结束后由系统释放。
  4. 文字常量区:常量字符串就是放在这里的。程序结束后由系统释放。
  5. 程序代码区:存放函数体的二进制代码。

举例来说:

//main.cpp 
int a = 0; // 全局初始化区 
char *p1; // 全局未初始化区 
main() 
{ 
int b; // 栈 
char s[] = "abc"; // 栈 
char *p2; // 栈 
char *p3 = "123456"; // 123456\0 在常量区,p3在栈上。 
static int c =0; // 全局(静态)初始化区 

// 分配的 10 个和 20 个字节的区域就在堆区。 
p1 = (char *)malloc(10); 
p2 = (char *)malloc(20); 

strcpy(p1, "123456"); // 123456\0 放在常量区,编译器可能会将它与p3所指向的"123456"优化成同一个位置
} 

在函数体中定义的变量通常是在栈上,用malloc, calloc, realloc等分配内存的函数分配得到的就是在堆上。

在所有函数体外定义的是全局量,加了static修饰符后不管在哪里都存放在全局区(静态区),在所有函数体外定义的static变量表示在该文件中有效,不能extern到别的文件使用,在函数体内定义的static表示只在该函数体内有效。

函数中的"123456"这样的字符串存放在常量区。

还有就是函数调用时会在栈上有一系列的保留现场及传递参数的操作。

关于堆和栈

1. 内存分配方面

堆: 一般由程序员分配释放,若程序员不释放,程序结束时可能由OS回收。它与数据结构中的堆是两回事,分配方式是类似于链表。可能用到的关键字如下:new、malloc、delete、free等等。

栈: 由编译器(Compiler)自动分配释放,存放函数的参数值,局部变量的值等。其操作方式类似于数据结构中的栈。当一个函数调用完返回后它会释放该函数中所有的栈空间。

2. 申请方式

栈(stack):

由系统自动分配。例如,声明在函数中一个局部变量 int b;,系统自动在栈中为b开辟空间。

堆(heap):

需要程序员自己申请,并指明大小。

在C中 malloc 函数:

p1 = (char *)malloc(10); 

在C++中用 new 运算符:

p2 = (char *)new char(10); 

但注意 p1、p2 本身是在栈中的。

3. 申请后系统的响应

栈: 只要栈的剩余空间大于所申请空间,系统将为程序提供内存,否则将报异常提示栈溢出。

堆: 首先应该知道操作系统有一个记录空闲内存地址的链表,当系统收到程序的申请时,会遍历该链表,寻找第一个空间大于所申请空间的堆结点,然后将该结点从空闲结点链表中删除,并将该结点的空间分配给程序。对于大多数系统,会在这块内存空间中的首地址处记录本次分配的大小,这样代码中的 delete 语句才能正确的释放本内存空间。另外,由于找到的堆结点的大小不一定正好等于申请的大小,系统会自动的将多余的那部分重新放入空闲链表中。

4. 申请大小的限制

栈:

  • 在 Windows 下,栈是向低地址扩展的数据结构,是一块连续的内存的区域。这句话的意思是栈顶的地址和栈的最大容量是系统预先规定好的,在 Windows 下,栈的大小一般是2M,如果申请的空间超过栈的剩余空间时,将提示 overflow。因此,能从栈获得的空间较小。
  • 栈不够用的情况一般是程序中分配了大量数组和递归函数层次太深。
  • 当一个函数调用完返回后它会释放该函数中所有的栈空间。

堆:

  • 堆是向高地址扩展的数据结构,是不连续的内存区域。这是由于系统是用链表来存储的空闲内存地址的,自然是不连续的,而链表的遍历方向是由低地址向高地址。堆的大小受限于计算机系统中有效的虚拟内存。由此可见,堆获得的空间比较灵活,也比较大。

5. 申请效率的比较

栈由系统自动分配,速度较快。但程序员是无法控制的。

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

6. 堆和栈中的存储内容

栈:

  • 在函数调用时,第一个进栈的是主函数后的下一条指令(函数调用语句的下一条可执行语句)的地址,然后是函数的各个参数(在大多数的C编译器中,参数是由右往左入栈的),然后是函数中的局部变量。注意静态变量是不入栈的。
  • 当本次函数调用结束后,局部变量先出栈,然后是参数,最后栈顶指针指向最开始存的地址,也就是主函数中的下一条指令,程序由该点继续运行。

堆:

  • 一般是在堆的头部用一个字节存放堆的大小。堆中的具体内容有程序员安排。

7. 存取效率方面

堆: char *s1 = "Hellow Word";是在编译时就确定的;

栈:char s1[] = "Hellow Word";是在运行时赋值的;用数组比用指针速度要快一些,因为指针在底层汇编中需要用edx寄存器中转一下,而数组在栈上直接读取。

在栈上存取数据比通过指针在堆上存取数据快些。


欢迎关注我的微信公众号【数据库内核】:分享主流开源数据库和存储引擎相关技术。

标题网址
GitHubhttps://dbkernel.github.io
知乎https://www.zhihu.com/people/…
思否(SegmentFault)https://segmentfault.com/u/db…
掘金https://juejin.im/user/5e9d3e…
开源中国(oschina)https://my.oschina.net/dbkernel
博客园(cnblogs)https://www.cnblogs.com/dbkernel
c# 32位程序突破2G内存限制 VS中32位程序突破2G内存限制 阅读详情

相关推荐

C/C++编译器内存优化技术:内存优化关注程序对内存的访问和使用,以提高内存访问速度和减少内存占用。

C/C++编译器内存优化技术:内存优化关注程序对内存的访问和使用,以提高内存访问速度和减少内存占用。

探索C++编程的奥秘,分享深入的技术见解和实践,旨在激发读者创造力与解决问题的思维。 3427

编译器介绍(一):编译器的内存分配策略

3. **栈区(stack)**:由编译器自动分配和释放,存放函数的参数值、局部变量的值等。其操作方式类似于数据结构中的栈。当函数被调用时,为其分配栈空间,函数返回时,相应的栈空间被释放。与栈区不同,堆区的内存分配和释放是由程序员控制的,通常通过malloc、calloc等函数进行分配,通过free函数进行释放。2. **数据段**:储存程序中的全局变量或静态变量,这些变量是程序员初始化过的。1. **文本段**:也称为代码区,存放C程序编译后的二进制指令代码,包括各种函数体内的代码翻译后的CPU指令。

MHD0815的博客 789

告别虚拟机!在WSL2的Ubuntu里5分钟跑通LVGL v9.2图形界面(附SDL2配置避坑)

本文详细介绍了如何在WSL2的Ubuntu子系统中快速配置LVGL v9.2图形库的SDL2模拟环境,帮助嵌入式开发者在5分钟内跑通第一个图形界面示例。通过WSL2和VSCode的远程开发插件,实现Windows系统下无缝使用Linux工具链,大幅提升开发效率。

weixin_28736335的博客 426

编译时的内存分配

编译时内存分配主要是指在程序编译阶段,由编译器为程序中的各种静态数据分配内存空间。这些静态数据包括全局变量、静态变量、常量等。这些内存分配在编译时就已经确定,在程序加载到内存后,这些内存空间会被操作系统分配并初始化。

Charizard_的博客 830

Windows 11“此应用已被管理员阻止运行”解决方案

通过本文介绍的两种方法,你应该能够解决Windows 11中“此应用已被管理员阻止运行”的问题。无论你选择创建新管理员账户还是禁用管理员批准模式,都请确保了解相关操作的风险,并根据你的实际需求做出选择。通过禁用“用户账户控制:以管理员批准模式运行所有管理员”设置,可以解决因系统安全设置导致的应用程序被阻止运行的问题。这种方法适用于那些希望简化管理员账户操作流程的用户,但需要注意可能带来的安全风险。通过创建并登录具有管理员权限的新账户,可以解决因系统安全设置导致的应用程序被阻止运行的问题。

mmoo_python的博客 1万+

等保三级-MySQL 安全加固实战指南

本文详细介绍了MySQL数据库在等保三级要求下的安全加固实战指南,涵盖身份鉴别、访问控制、安全审计、网络传输安全、入侵防范和数据完整性等关键领域。通过具体配置示例和实战经验,帮助用户有效提升MySQL数据库的安全防护能力,满足等保三级合规要求。

weixin_29197835的博客 183

【程序员也要懂点底层】编译器对内存的分配

【程序员也要懂点底层】编译器对内存的分配

优快云GuoYuying的博客 1760

基于Open Cluster Management构建企业级多Kubernetes集群管理平台OpenClaw

在云原生架构中,Kubernetes已成为容器编排的事实标准。随着业务规模扩大,企业往往需要管理分布在多个云环境或数据中心的Kubernetes集群,这带来了集群管理、应用分发、策略统一和监控运维等复杂挑战。多集群管理技术通过提供统一控制平面,实现了对分布式资源的集中管控,其核心价值在于提升运维效率、保障安全合规并降低管理成本。Open Cluster Management(OCM)作为CNCF沙箱项目,采用Kubernetes原生架构,通过自定义资源定义(CRD)和控制器模式,为构建多集群管理平台提供了标

weixin_33747129的博客 369

程序的编译,链接,运行和地址映射

1.在x86体系32位linux内核/操作系统下:每一个进程在运行的时候,系统会为其分配一个以上构造的4G的虚拟地址空间:3G为用户空间(私有)1G为内核空间(共享)代码段:存放程序的执行代码,大小在运行前已经确定,也包含一些只读的常数变量,例字符串常量等。数据段:存放程序中已初始化的全局变量(静态分配内存)。堆区:用于存放进程运行中被动态分配的内存段,大小不固定,可动态扩张或缩减。 当...

weixin_40365003的博客 2215

wxComboBox类的使用方法及示例代码

其中,parent表示该控件的父窗口,ID_COMBOBOX是该控件的ID,用于在事件处理函数中区分不同的控件,"默认选项"是下拉列表框的默认选项,options是wxArrayString类型的数组,用于存储下拉列表框中的选项,style可以指定wxComboBox的样式。wxComboBox是wxWidgets中的一个常用控件,它可以被用来显示一组在下拉列表框中的选项,并允许用户从中选择一个选项。上述就是wxComboBox类的基本使用方法,使用这个控件可以方便地实现下拉列表框的功能。

学习使你进步。 714

【图像拼接(Image Stitching)】关于【图像拼接论文精读】专栏的相关说明,包含专栏使用方法、阅读顺序、创新思路、文章汇总、源码汇总、数据集汇总等。总之,【图像拼接论文相关】看这一篇就够了

为什么会有这篇文章?因为专栏简介里写不下太多东西,只能通过这篇文章和大家交流,算是一个专栏阅读指南吧。说点心里话本来吧,我只想用优快云来记录自己学习【图像拼接】领域论文的过程,对每篇文章有个细致的理解,方便自己反复查阅。设置为付费也是因为涉及论文和本人其他项目需要,防止查重和其他问题,所以价格最开始设置的是专栏付费价格里最高的。起初,确实没有人看,一切也都平淡地度过着。

主要更新底层视觉(去噪、超分等)相关的科研内容,形式为【论文精读】+【论文复现】 4万+

编译原理 - 栈变量地址分配

说明 变量地址在编译期就由编译器确定了(栈变量也一样,不同的是栈变量确定的是栈偏移),程序运行时才做真正的内存分配。 栈空间由高地址往低地址分配。 问题 编译器处理栈变量地址分配有什么规则? 后续测试,测试环境如下: Linux : gcc (Ubuntu 4.8.4-2ubuntu1~14.04.4) 4.8.4 windows : Code::Blocks 17.12 普通局部变量 int main(int argc, char **argv){ int a; char b; int

qazw9600的专栏 1391

【信息系统项目管理师】高分论文:论信息系统项目的整合管理(绩效考核系统)

我们将项目管理计划中的子计划包括项目范围、进度、成本、质量管理计划,过程改进计划,人力资源管理计划,风险、采购管理计划,干系人管理计划,项目范围、成本、进度基准作为依据,查看项目的各个方面,通过组织全体团体成员会议来解读由各监控过程提供的信息,之后我与项目管理团队一起制订所需措施,确保项目绩效达到预期要求。在一个项目中,变更是必然的,也是不可避免的,进度拖延,成本失控,客户有新的需求等都会引起项目的变更。在本项目中,我要求有处于工作状态的产品,开发人员才可以对其任意修改,修改完成后,重新入库即可。

数据知道的博客 6888

C语言:内存分配

一,内存分配 1,内存分配的类型: 在C/C++中内存分为5个区,分别为栈区、堆区、全局/静态存储区、常量存储区、代码区。 静态内存分配:编译时分配。包括:全局、静态全局、静态局部三种变量。 动态内存分配:运行时分配。包括:栈(stack): 局部变量。堆(heap): c语言中用到的变量被动态的分配在内存中。(malloc或calloc、realloc、free函数) 2.变量的内存分...

ymj321的专栏 4749

aic8800出现insmod: can‘t insert ‘/lib/modules/4.9.191/aic8800_fdrv.ko‘: No such device

2、如果单独编译wifi驱动,则把CONFIG_PLATFORM_UBUNTU?= y都改为CONFIG_PLATFORM_ALLWINNER?1、如果把wifi驱动嵌入到内核编译,则在makefile中加入这一句。后面再修改对应平台的交叉编译链和内核吗路径等。

mantouyouyou的博客 512

STM32F407中文手册

STM32f407中文手册 本参考手册面向应用开发人员,提供有关使用 STM32F405xx/07xx、STM32F415xx/17xx、 STM32F42xxx 和 STM32F43xxx 微控制器存储器与外设的完整信息。STM32F405xx/07xx、STM32F415xx/17xx、STM32F42xxx 和 STM32F43xxx 构成一个微 控制器系列,各产品具有不同的存储器大小、封装和外设。有关订购信息以及器件的机械与电气特性,请参见数据手册。有关 ARM Cortex™-M4F 内核的信息,请参见《Cortex™-M4F 技术参考手册》。

MCU内存分配与管理

C语言内存分配 一、内存分配 ​ 1、内存分配的类型: 在C/C++中内存分为5个区,分别为栈区、堆区、数据段(初始化数据区/静态数据区、未初始化数据区;或者是只读数据段Ro-data即常量数据,已经初始化读写数据段(RW-data),未初始化数据段即BBS(ZI-data))、代码区。 静态内存分配:编译时分配。包括:全局、静态全局、静态局部三种变量。 动态内存分配:运行时分配。包括:栈(stack): 局部变量。堆(heap): c语言中用到的变量被动态的分配在内存中。(malloc或.

weixin_40543589的博客 5717

OV9734 DATASHEET,完整规格书

OV9734完整规格书,包括电气参数,尺寸规格,寄存器配置表等

程序编译后运行时的内存分配

1.程序编译时的运行状况

Moliay的博客 1299

精雕软件(JDpaint) 5.5 绿色版

精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

C语言(十三)-内存分配

一个由c/C++编译的程序占用的内存分为以下几个部分 1、栈区(stack)— 程序运行时由编译器自动分配,存放函数的参数值,局部变量的值等。其操作方式类似于数据结构中的栈。程序结束时由编译器自动释放。 2、堆区(heap) — 在内存开辟另一块存储区域。一般由程序员分配释放, 若程序员不释放,程序结束时可能由OS回收 。注意它与数据结构中的堆是两回事,分配方式倒是类似于链表。 3、全局区(静态区)(st...

qhu1600417010的博客 612

开源输入法框架解析:IME实现流程与拼音编码

输入法是操作系统中的基础软件,负责将键盘按键序列转换为自然语言文本。其底层原理依赖于编码方案与词库匹配,常见的有全拼、双拼等拼音编码方案。IME(输入法编辑器)实现流程涵盖了输入事件捕获、上下文解析、候选词生成和上屏提交等环节。基于模块化设计的开源输入法框架(如Fcitx、IBus)提供了可扩展的接口,使得开发者能够灵活定制词库和算法,从而提升输入效率和用户体验。这些技术广泛应用于桌面办公、移动互联及智能嵌入式设备。理解开源输入法框架的架构与IME实现流程,有助于工程实践者快速构建高性能输入工具。

weixin_33755649的博客 299

Keil MDK编译器内存分配

CODE、RO、RW、ZI Data 域及堆栈空间    Keil MDK编译器完成编译链接后,在调试窗口会出现Code,RO,RW,ZI 四种内存分配区域,下面说明其中的意思。 Code区:即代码区。该区域除了存放指令外,还包括指令数据(inc .data),如局部变量数组的初始化值。当函数被调用时,该函数用code区内指令数据来初始化堆栈区内分配的局部变量数组。注:局部变量用立即数来赋...

zuixin369的博客 5497

程序的内存分配方式

程序的内存分配方式

m0_48739934的博客 1167

[C++]内存分配

转载自:http://www.cnblogs.com/pengrui/archive/2011/04/02/2002841.html 一、程序内存分配的基本知识 一个由C/C++编译的程序占用的内存分为以下几个部分: 1、栈区: 由编译器自动分配释放 ,存放函数的参数值,局部变量的值等。其操作方式类似于数据结构中的栈。 2、堆区:一般由程序员分配释放, 若程序员不释放,程序结束时...

A5656665656556的博客 385

C语言:内存分配---栈区、堆区、全局区、常量区和代码区

1. 栈区 栈区介绍 栈区由编译器自动分配释放,由操作系统自动管理,无须手动管理。 栈区上的内容只在函数范围内存在,当函数运行结束,这些内容也会自动被销毁。 栈区按内存地址由高到低方向生长,其最大大小由编译时确定,速度快,但自由性差,最大空间不大。 栈区是先进后出原则,即先进去的被堵在屋里的最里面,后进去的在门口,释放的时候门口的先出去。 存放内容 临时创建的局部变量和const定义的局部变量存放在栈区。 函数调用和返回时,其入口参数和返回值存放在栈区。 2. 堆区 堆区介绍 堆区由程序员分配内存和释放

MQ0522的博客 4万+

内存中堆栈

一个由c/C++编译的程序占用的内存分为以下几个部分 1、栈区(stack)— 程序运行时由编译器自动分配,存放函数的参数值,局部变量的值等。其操作方式类似于数据结构中的栈。程序结束时由编译器自动释放。 2、堆区(heap) — 在内存开辟另一块存储区域。一般由程序员分配释放, 若程序员不释放,程序结束时可能由OS回收 。注意它与数据结构中的堆是两回事,分配方式倒是类似于链表。 3、全局

4858

编译器对变量的内存分配方式 收藏

问题来源:高人指点啊!!!!<br />假如:定义int  a=4;<br />要不要把a和4都存放到内存呢??? <br />深圳小小(812890249) 20:52:14 <br />“要不要”是什么意思? <br />亮剑<custliuyalong@qq.com> 20:52:30 <br />是不是 <br />深圳小小(812890249) 20:52:44 <br />a不会吧 <br />亮剑<custliuyalong@qq.com> 20:52:47 <br />是不是把a和4都存放到

IT人生 1269
上一篇: 推荐 | 一体化实时 HTAP 数据库 StoneDB,如何替换 MySQL 并实现近百倍性能提升
下一篇: 特性介绍 | PostgreSQL 的依赖约束详解 - 系统表 pg_depend & pg_constraint
dbkernel
博客等级 码龄4年 60粉丝 42原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值