当然这个图对于stm32的地址顺序是不对的,stm32 text在0x0800 0000 开始的,sram在0x02000 0000开始的,但是init data ,bss,heap和stack的顺序是对的,内存中就是这样排列的。
首先看这个图程序由下边几部分构成的,bss,initial data ,code,heap,stack
本来想记录下bss和initial的区别,但是我在stm32下查看bss和initial data规律好像跟我理解的不一样。好像比较乱,那就不记录了。
在stm32的启动文件中,定义了堆栈的大小,所以内存中是这样安排的,显示按照使用的全局变量的大小来从0x0200 0000分配,分配完毕以后,就是堆得内存开始分配,然后紧接着是栈的内存,但是栈是向下生长的,所以对于stm32,
我们的程序使用了64+1832= 1896=0x768 ,那么栈顶就是0x0200 0000 +0x768,
R13就是栈顶地址,接下来是堆,然后再是全局变量。堆是malloc中分配的,head是给局部变量用的这里就不多说了。所以知道了内存的模型,怎样才能最大化的使用内存呢,假如我的单片机是16k的内存,但是我的全局变量用了1k,我的堆在启动文件中分配了1k,栈也是分配了1k,那么由于栈是向下生长的,那是不 是意味着我其他的16-1-1-1的sram就浪费了,答案是肯定的。所以我觉得留够栈空间和全局变量空间,其他的都分配给堆,就这个例子而言,堆应该为14k。
思考一个问题,如果堆栈大小分配不合适了还有什么危害?在内存中是没有明确的界限的,栈向下生长,堆向上生长,会造成重叠,假如局部变量很大,一直生长到了堆得位置,那就会改变全局变量的值,这就会出现全局变量的值被莫名的改变。
那又考虑,为什么会有这种缺陷,设计者为什么要设计为栈向下生长,堆向上生长。
假如都向上生长其实也会有这个问题,都向上生长还会出现在程序使用的时候内存越界。如果有一个向下生长,内存越界编译的时候就被发现了。
其实说来说去还有一个问题没有讨论,那就是字符串常量在哪里存储哪?
存储在静态存储区,就是initial data哪里。
看一个面试题
char str1[] = "abcd";
char str2[] = "abcd";
const char str3[] = "abcd";
const char str4[] = "abcd";
const char *str5 = "abcd";
const char *str6 = "abcd";
char *str7 = "abcd";
char *str8 = "abcd";
( str1 == str2 ) //错误
( str3 == str4 ) //错误
( str5 == str6 ) //正确
( str7 == str8 ) //正确
其实可以取值&("abcd")打印出这个字符串常量的地址,然后根据上边的内存表的位置安排,看看在内存中的位置就知道了。我这里就不做实验了。对于字符串常量,https://blog.csdn.net/chun_1959/article/details/21650761讲解的比较好
看了这篇文章,思考一下,为什么用static修饰的局部变量的值不会丢失了吗?