单片机内程序运行的时候ram空间是如何分配的?

转自:http://blog.sina.com.cn/s/blog_a575eb9401014tam.html

单片机内程序运行的时候ram空间是如何分配的?
我现对一个程序进行减少片内ram的使用的优化,有一些效果,同时也产生了些疑问,在此向各位大虾请教:
一、现象:
1、    我在通过减少全局变量、函数内变量的使用,减少函数间参数传递等手段来优化,发现某些时候我减少一个变量的使用,keil编译的结果就显示data减少了一字节,有时候这样一直减少几个变量的使用,data值一直都不会变,接着再减少变量的使用,又会一个一个的减少,到后来又不减少了。
2、    我屏蔽程序中一些代码之后编译,显示data反而是增加了。
二、疑问:
1、单片机程序运行的时候,内部ram是如果分配管理的,data值由哪些部分组成?
2、之前描述的两个现象如何解释?
3、data值是不包括堆栈空间的,那么程序运行的堆栈空间大概需要多少,和哪些因素有关,能不能预估?
4、单片机片内ram的使用限度是多少?(指keil编译出来的data值最好不要超过多少)

答:单片机内程序运行的时候ram空间是如何分配的
1、RAM的分配是与你选择的编译模式有关,你可以看下编译器的手册,再打开最后产生的分配对照表仔细对照源程序,应该可以找到规律。

2、仍然与编译模式有关,通常全局变量数量的变化可以立即反映在data段的长度上,但如果局部变量是指定用堆栈,就不一定会反映在data段的长度上了。

3、堆栈空间与你的RAM空间的分配有关,这是在连接时确定的,在链接描述文件中指定的。

4、RAM的使用限度当然跟你的单片机RAM的大小有关。

对不起,我对Keil的环境不熟,我不能帮你解释具体到Keil上如何;上面讲的是基本原理,每个C语言的环境都是这样。

谢谢平常人!若有机会到广佛一带,我请你喝酒!
keil编译模式我选择的small:variables in data模式,大家一般也都应该是这个模式吧。变量都是定义到data/idata区的。
keil编译结果和编译器本身有关,就算是不同的编译器,在内存分配上是不是有共同遵从的方法呢?
或者您能不能介绍其他某个编译器的内存分配方式呢?

通常全局变量数量的变化可以立即反映在data段的长度上,但如果局部变量是指定用堆栈,就不一定会反映在data段的长度上了。
re:你的意思是局部变量占用的空间的使用还不一定包含到编译结果里了?我编译的结果是200多字节的data,由哪些组成?

ram使用限度跟单片机有关,那好比我的单片机片内ram是256的,那我使用的空间(也就是keil编译出来的结果)的限度是多少,或者和哪些有关?也就是通常做法,我要留给堆栈多少空间?

另外再问一下:
同一个程序生成的bin文件和hex文件在大小上有什么关系?
听说bin会是hex的一半?
这两个文件在使用中有什么区别?

变量在内存的分配方式
通常单片机的RAM区可以分成3类,短地址区、长地址区和外部地址区。

短地址区一般指00-FF之间可以用8位地址访问的区域,长地址区一般指0100-FFFF之间必须用多于8位的地址访问的区域,外部地址区指CPU外部总线访问的区域,不同的区域有不同的指令寻址方式,例如:
MOV A, 40H ;访问短地址区
MOV A, @DPTR ;访问长地址区

一般的51中没有外部地址区。

根据用途还划分了一个堆栈区。

不同的存储分配模式决定了全局变量是放在那个区域,访问短地址区的指令可能比访问长地址区的指令短且快,但长地址区可容纳较多变量,尤其是较大的数组。

局部变量有两种分配策略,一种是放在堆栈中,因为局部变量只在他所在的函数中有效,出了这个函数退栈就可以清理掉局部变量所占空间,空间可重复利用。这种策略下,减少局部变量的使用并反映不出内存占用量的减少,因为内存的占用是动态的。

另一种策略是分析函数调用关系,把局部变量放在某段特定的内存区,如下例:
func1()
{
CHAR c1, c2;
....
}

func2()
{
CHAR x1, x2, x3;
...
}

main()
{
func1();
func2();
....
}

编译器发现func1与func2没有调用关系,就把c1与x1分配到同一个地址,c2与x2分配到同一个地址,x3分配到另一个地址;这样处理可以比堆栈的方法得到较高的效率。当你减掉c1时,并没有减少内存的总用量。

所以,堆栈的长度要看你程序的调用关系,局部变量的使用策略等因素,根据实际情况决定。

至于bin与hex文件的区别,我的理解bin是用二进制的形式存放可执行代码,而hex文件使用ASCII形式存放可执行代码;如
  0x12, 0x34, 0x56  bin文件
  1 2 3 4 5 6 hex文件

你说他们的大小是什么关系?

对不起,我只能讲这么多了,再讲就可以写一本书了。

时间: 2024-12-11 14:11:14

单片机内程序运行的时候ram空间是如何分配的?的相关文章

Linux下程序运行时内存状态及相应查看工具

最近在解决一个编译问题时,一直在考虑一个问题,那就是Linux下可执行程序运行时内存是什么状态,是按照什么方式分配内存并运行的.查看了一下资料,就此总结一下,众所周知,linux下内存管理是通过虚存管理的,在分配内存是并非在物理内存开辟了一段空间,而是在使用时才分配的,而且是通过段页式管理.以上比较废话,开始看看程序运行时内存会是什么状态. 在linux下内存分配是以页为单位的,而页是通过段管理,各个段之间是独立的,方便管理.linux程序运行时,可以分为以下几个内存段: 一.BSS段 (bss

21ic编辑推荐:从单片机开始的程序运行

一直不清楚单片机中程序的执行过程,就是知道一个程序总是从一个main函数开始执行,然后把程序段存放在ROM里面,动态数据存放在RAM里面,而单片机的RAM资源又是及其的稀少,所以要省着用,但是到底怎么个省着用法,我也是云里雾里,这可能就要涉及到具体代码的优化,而且建立在对单片机系统和C的深入理解基础上.这些将在日后逐渐学习. 在这篇文章里面提到,我们用单片机编程然后在硬件上跑程序都是裸机编程,这和我们电脑 上面的程序运行机制略有不同,电脑上面的程序都是在电脑的操作系统上面跑的,而操作系统就相当于

在程序运行过程中,对象所占的空间是不能随时释放的

使用类名定义的对象(请查看:C++类的声明和对象的定义)都是静态的,在程序运行过程中,对象所占的空间是不能随时释放的.但有时人们希望在需要用到对象时才建立对象,在不需要用该对象时就撤销它,释放它所占的内存空间以供别的数据使用.这样可提高内存空间的利用率. 在C++中,可以使用new运算符动态地分配内存,用delete运算符释放这些内存空间(请查看:C++动态分配内存(new)和撤销内存(delete)).这也适用于对象,可以用new运算符动态建立对象,用delete运算符撤销对象. 如果已经定义

2.C语言------程序运行为什么需要内存2

C语言------程序运行为什么需要内存(二) 1.代码就是函数.C语言中全局变量和局部变量就是数据. 2.在运行应用程序时,所有应用程序的代码和数据都在DRAM中就是冯诺依曼结构. 3.在单片机中将程序烧写到Flash(NorFlash)中,然后程序在Flash中运行.如果程序运行过程中不需要处理数据,那么这个这个程序也就不需要内存.程序中涉及到的数据(全局变量或局部变量)不能再Flash中必须放到RAM(SRAM:内存)中.CPU从Flash中读取程序并运行该程序,Flash中的程序只会被读

STM32启动时RAM空间堆(Heap)和栈(stack)的分配 总结

STM32再启动的时候RAM首先分配给使用到的全局变量,及调用库占用的一些数据(不太清楚是什么数据) ,然后再将剩余的空间分配给Heap和stack. 以下是网上关于Heap和Stack的说: (1)栈区(stack):由编译器自动分配和释放,存放函数的参数值.局部变量的值等,其操作方式类似 于数据结构中的栈. (2)堆区(heap):一般由程序员分配和释放,若程序员不释放,程序结束时可能由操作系统回收.分配 方式类似于数据结构中的链表. (3)全局区(静态区)(static):全局变量和静态变

苹果IOS,与windows Phone7,系统,内存,CPU处理,及后台程序运行,详解微软墓碑机制的系统

关于ios的多任务以及内存管理 看了很多人为自己的可用内存是350mb还是380mb纠结.为了多优化出一点可用内存费脑筋. ios的任务管理和内存管理,跟windows是有很大差别的.很多人习惯于用 windows的思维去看待ios. windows大家都知道,窗口开的越多,系统越慢,为什么呢?因为所有窗口都在运行,cpu占用率高:并且都占内存.可用内存不足还会迫使系统使用硬盘充当虚拟内存,硬盘频繁读写当然会多耗电,并且硬盘速度也比较慢. ios则不同.首先ios的后台任务,除了极少数可以后台运

杂谈——Android从启动到程序运行发生的事情

转载请注明出处 博客地址:http://blog.csdn.net/JonsTank2013/article/details/51118563 作者:李中权 前言 好久没有写博客了,瞬间感觉好多学了的东西不进行一个自我的总结与消化总归变不成自己的.通过博客可能还可以找到一些当初在学习的时候没有想到的问题.想了半天,从大二上学期自学Android以来还没有对Android从启动到程序运行期间进行一个完整的归纳,刚好最近又学到了一些新东西,那就以这篇博客为媒介,总结一下从Android启动到程序运行

Android从启动到程序运行整个过程的整理

1Android是基于Linux的一个操作系统,它可以分为五层,下面是它的层次架构图,可以记一下,因为后面应该会总结到SystemServer这些Application Framework层的东西 Android的五层架构从上到下依次是:应用层,应用框架层,库层,运行时层,Linux内核层. 而在Linux中,它的启动可以归为一下几个流程: Boot Loader——>初始化内核——>...... 当初始化内核之后,就会启动一个相当重要的祖先进程,也就是init进程,在Linux中所有的进程都

linux下实现在程序运行时的函数替换(热补丁)【转】

转自:http://www.cnblogs.com/leo0000/p/5632642.html 声明:以下的代码成果,是参考了网上的injso技术,在本文的最后会给出地址,同时非常感谢injso技术原作者的分享. 但是injso文章中的代码存在一些问题,所以后面出现的代码是经过作者修改和检测的.也正因为这些错误,加深了我的学习深度. 最近因为在学习一些调试的技术,但是很少有提到如何在函数运行时实现函数替换的. 为什么会想到这一点?因为在学习调试时,难免会看到一些内核方面的调试技术,内核中的调试