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进行内存释放,否则会造成内存泄漏。
如果程序员没有释放掉,那么在程序结束后,操作系统会自动回收。