首页 > 代码库 > STM32的堆与栈与编译信息查看

STM32的堆与栈与编译信息查看

STM32的堆与栈与编译信息查看

因为一个项目中使用malloc函数动态分配内存400多个字节,返回为0,分配失败。查找失败原因,为堆空间不足分配导致。查看堆和栈分别设置了2K,按正常情况看应能满足分配空间,原因可能因为栈分配空间不够,导致到堆的内存空间致使,堆的内存空间过小。下面就说一下STM32的RAM区的分配,堆和栈的信息和编译信息查看。

以下引用网上资料 理解堆和栈的区别和KEIL打印信息的理解

(1)栈区(stack):由编译器自动分配和释放,存放函数的参数值、局部变量的值等,其操作方式类似

于数据结构中的栈。

(2)堆区(heap):一般由程序员分配和释放,若程序员不释放,程序结束时可能由操作系统回收。分配

方式类似于数据结构中的链表。

(3)全局区(静态区)(static):全局变量和静态变量的存储是放在一块的,初始化的全局变量和静态

变量在一块区域,未初始化的全局变量和未初始化的静态变量在相邻的另一块区域。程序结束后由系

统自动释放。

(4)文字常量区:常量字符串就是存放在这里的。

(5)程序代码区(FLASH):存放函数体的二进制代码。

例如:

int a=0;   //全局初始化区

char *p1;   //全局未初始化区

main()

{

int b;   //栈

char s[]="abc";   //栈

char *p3= "1234567";   //在文字常量区Flash

static int c =0 ;   //静态初始化区

p1= (char *)malloc(10);   //堆区

strcpy(p1,"123456");   //"123456"放在常量区

}

所以堆和栈的区别:

stack的空间由操作系统自动分配/释放,heap上的空间手动分配/释放。

stack的空间有限,heap是很大的自由存储区。

程序在编译期和函数分配内存都是在栈上进行,且程序运行中函数调用时参数的传递也是在栈上进行。

在keil的Build时会有打印(在IAR里没有看到有打印信息)

Program Size:Code=XX  RO-data=http://www.mamicode.com/XX   RW-data=XX   ZI-data=XX

其中:

Code: 存储到flash[Rom]中的程序代码。

RO-data:(Read Only)只读常量的大小,如const型。

RW-data:(Read Write) 初始化了可读写变量的大小。即已初始化为非零的全局变量。

ZI-data:(Zero Initialize) 没有初始化或初始化为0的可读写的变量的大小(不会被算做代码里,因为不会被初始化)。

ROM(Flash) size = Code+RO-data+RW-data;

RAM size = RW-data+ZI-data

如果一个变量被初始化为0,则该变量的处理方法与未初始化变量一样放在ZI区法域。即ARM C程序中,所有的示初始化变量都会被自动初始化为0。

总结:

1、C中的指令以及常量被编译后是RO类型数据

2、C中的未被始化或初始化为0的变量编译后是ZI类型数据。

3、C中已被初始化成非0的值的变量编译后是RW类型数据

4、以上变量指全局变量,局部变量是以上程序中在栈中分配。

ROM指:NAND Flash,Nor Flash

RAM指:PSRAM,SDRAM,DDRAM

Keil IDE的编译信息在工程文件夹的xx.map文件中,STM32的RAM分区从0x0200 0000开始,静态区、堆、栈。

所有的全局变量,包括静态变量之类的,全部存储在静态存储区。然后是堆区(如没用到malloc,则没有该区),之后是栈区,栈在程序中存储局部变量。

; Amount of memory (in bytes) allocated for Stack

; Tailor this value to your application needs

; <h> Stack Configuration

;   <o> Stack Size (in Bytes) <0x0-0xFFFFFFFF:8>

; </h>

Stack_Size      EQU     0x00000400

                AREA    STACK, NOINIT, READWRITE, ALIGN=3

Stack_Mem       SPACE   Stack_Size

__initial_sp

; <h> Heap Configuration

;   <o>  Heap Size (in Bytes) <0x0-0xFFFFFFFF:8>

; </h>

Heap_Size       EQU     0x00000200

                AREA    HEAP, NOINIT, READWRITE, ALIGN=3

__heap_base

Heap_Mem        SPACE   Heap_Size

__heap_limit

这里定义了堆栈各自大小,堆:512bytes 栈1k;

所以栈区大小有限制,我们在局部变量中不要定义大数组否则容易溢出。

查看xx.map文件

  Removing Unused input sections from the image.就是将库中没有用到的函数从可执行映像中删除掉,减小程序的体积。第一行

    Removing startup_stm32f10x_md.o(HEAP), (512 bytes).

意思是因为没有使用malloc动态分配内存,所以没有分配堆。

==============================================================================

Image Symbol Table

    Local Symbols      符号表里的局部符号。

    Symbol Name             Value     Ov Type        Size  Object(Section)

最后一项

    STACK                  0x2000560  Section     1024  startup_stm32f10x_md.o(STACK)

    Global Symbols     符号表里的全局符号

    Symbol Name             Value     Ov Type        Size  Object(Section)

最后一项

    __initial_sp          0x2000960   Data           0  startup_stm32f10x_md.o(STACK)

STACK是栈底,__initial_sp 栈顶地址,此地址被存在Flash0x0800 0000中,占用四个字节。

所以栈大小 为 0x400 即1024个字节。

再加入malloc看一下:

HEAP                                      0x20000568   Section      512    startup_stm32f10x_md.o(HEAP)  
STACK                                    0x20000768   Section     1024   startup_stm32f10x_md.o(STACK)  
__heap_base                         0x20000568   Data           0       startup_stm32f10x_md.o(HEAP)  
__heap_limit                          0x20000768   Data           0       startup_stm32f10x_md.o(HEAP)  
__initial_sp                             0x20000b68   Data           0      startup_stm32f10x_md.o(STACK)

可见分配了堆,大小为512 bytes在栈的下面,这里也可以看出, 堆向上增长,栈向下增长

如果栈分配的空间不足,将会占用堆的空间,malloc时,可能因为堆空间不足,导致不能分配内存。

要想分配堆空间和栈空间的大小可以设置启动文件的和Heap_Size和Stack_Size的值,随着堆分配和栈分配空间加大,此时编译后看到ZI-data将相应变大,但这个并不是真正的变大,只是分配了较大的空间,可能并没有使用。

网上还有把栈顶直接分配到RAM的最高处,这样不管如何分配栈空间,基本不会导致内存溢出。

另外此文中的.map里的例子,也是直接引用网上的内容!

将我的与非博客搬到博客园!

-----------------------------

STM32的堆与栈与编译信息查看