C---内存使用

1. 变量初始化

变量在使用之前应该被初始化。未初始化的变量的值是未定义的,可能包含任意的垃圾值

全局变量和静态变量:

  • 整型变量(int、short、long等):默认值为0。
  • 浮点型变量(float、double等):默认值为0.0。
  • 字符型变量(char):默认值为’\0’,即空字符。
  • 指针变量:默认值为NULL,表示指针不指向任何有效的内存地址。

局部变量:(在函数内部定义的非静态变量)
不会自动初始化为默认值,它们的初始值是未定义的(包含垃圾值)。因此,在使用局部变量之前,应该显式地为其赋予一个初始值。

2. 内存占用

基本的编译软件,在编译后的Build Output里面均有代码内存占用的基本情况,接下来以keil软件为例进行介绍

2.1 存储大小

Program Size: Code=6104 RO-data=380 RW-data=116 ZI-data=19316  //单位字节

1. Code程序代码部分,即CPU执行的指令大小
2. RO-data(Read-Only-Data):程序中的只读数据,程序中的字符串常量及用const定义的常量,枚举值,在程序执行期间不会被修改
3. RW-data(Read-Write-Data)已经初始化的全局变量、静态变量等,在程序执行期间可能会被修改。
4. ZI-data(Zero-Initialize-Data):以0初始化的变量,如未初始化的全局变量、静态变量

局部变量: 局部变量通常存储在栈(Stack)上。栈是一种后进先出(LIFO)的数据结构,用于存储函数调用过程中的局部变量、函数参数、返回地址等信息。每当函数被调用时,就会为该函数的局部变量分配栈空间;当函数返回时,这些栈空间会被释放,以供后续的函数调用使用。
因此,局部变量的大小和数量会影响栈的使用情况,但不会直接反映在程序大小(Code, RO-data, RW-data, ZI-data)的统计中。在嵌入式系统或资源受限的环境中,需要特别注意栈的使用,以避免栈溢出等问题。

在编译出来的map文件中也有占用内存大小的相关描述

Total RO  Size (Code + RO Data)                 6484 (   6.33kB)
Total RW  Size (RW Data + ZI Data)             19432 (  18.98kB)
Total ROM Size (Code + RO Data + RW Data)       6600 (   6.45kB)

2.2 存储位置

1. Code:存在ROM/Flash,
2. RO-data(Read-Only-Data):存在ROM/Flash,
3. RW-data(Read-Write-Data):存在ROM/Flash,上电后搬至RAM .data段
4. ZI-data(Zero-Initialize-Data)存在RAM .bss段
5. 局部变量:局部变量通常存储在栈(Stack)

在这里插入图片描述

程序占用空间要求如下:
ROM大小=Code+RO-data+RW-data
RAM大小=RW-data+ZI-data

2.2 代码执行

在嵌入式系统中,通常有两种方式来运行程序代码:
1. 直接在FLASH中运行:在这种方式下,程序代码存储在FLASH存储器中,并直接从FLASH中执行。这种方式的优点是节省RAM空间,因为不需要将程序代码复制到RAM中运行。但缺点是,FLASH访问速度相对较慢,可能会影响程序的执行速度。

2. 将程序代码搬到RAM中运行:在这种方式下,程序代码首先从FLASH中复制到RAM中,然后再在RAM中执行。这种方式的优点是提高了程序执行的速度,因为RAM的访问速度通常比FLASH快。但缺点是需要额外的RAM空间来存储程序代码,可能会增加系统成本。选择哪种方式运行程序代码取决于具体的应用场景和需求。

对于一些对程序执行速度要求较高的应用,可能会选择将程序代码搬到RAM中运行;而对于一些对RAM空间要求较高或者程序执行速度要求不是很高的应用,可能会选择直接在FLASH中运行程序代码。

3. 程序内存分区中的堆与栈

3.1 栈(Stack)

栈由操作系统自动分配释放 ,用于存放函数的参数值、局部变量等,其操作方式类似于数据结构中的栈
在这里插入图片描述

其中函数中定义的局部变量按照先后定义的顺序依次压入栈中,也就是说相邻变量的地址之间不会存在其它变量栈的内存地址生长方向与堆相反,由高到底,所以后定义的变量地址低于先定义的变量,比如上面代码中变量 s 的地址小于变量 b 的地址,p2 地址小于 s 的地址。栈中存储的数据的生命周期随着函数的执行完成而结束。

总结:
栈一般存放局部变量和函数参数,从RAM的高地址,向下生长
•临时创建的局部变量存放在栈区。
•函数调用时,其入口参数存放在栈区。
•函数返回时,其返回值存放在栈区。
•const定义的局部变量存放在栈区。

3.2 堆(Heap)

一块空闲的内存,由开发人员分配和释放, 若开发人员不释放,程序结束时由 OS 回收分配方式类似于链表
malloc:从堆里划出一块空间给程序使用
free:用完后再把它标记为“空闲的”,可以再次使用
在这里插入图片描述

其中 p1 所指的 10 字节的内存空间与 p2 所指的 10 字节内存空间都是存在于堆。堆的内存地址生长方向与栈相反,由低到高,但需要注意的是,后申请的内存空间并不一定在先申请的内存空间的后面,即 p2 指向的地址并不一定大于 p1 所指向的内存地址,原因是先申请的内存空间一旦被释放,后申请的内存空间则会利用先前被释放的内存,从而导致先后分配的内存空间在地址上不存在先后关系。堆中存储的数据若未释放,则其生命周期等同于程序的生命周期

总结:
从RAM的低地址,向上生长
堆区用于存放程序运行中被动态分布的内存块,可增可减。他们的释放编译器不去管,由我们的应用程序去控制。
可以有malloc等函数实现动态分布内存。
有malloc函数分布的内存,必须用free进行内存释放,否则会造成内存泄漏。
如果程序员没有释放掉,那么在程序结束后,操作系统会自动回收。

  • 35
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值