关于协议栈XDATA,内存溢出的小结
【第二部分的内容仅供参考,自己不是十分确定】
**************************************************************
**************************************************************
**************************************************************
一、
1、单片机的存储器分为数据存储器(RAM)和程序存储器(ROM/FLASH):
RAM:用来存取各种动态的输入输出数据,中间计算结果以及与外部存储器交换的数据和暂存数据。设备掉电后,数据就会丢失。
ROM:通常用来固化存储一些用户写入程序或数据,用于启动设备和控制设备工作方式。设备掉电后可保存数据。
FLASH:通常也是用来固化存储一些用户写入程序或数据。设备掉电后不会丢失数据,同时可以快速读取数据。U盘、MP3多用这种存储器。
RAM包括:
(1)静态RAM(SRAM):速度非常快,是目前读写最快的存储设备。
(2)动态RAM(DRAM):保留数据时间短,但速度比ROM快,计算机内存多为DRAM。DRAM包括:EDORAM;DDR RAM;RDRAM;SGRAM;WRAM…
ROM包括:
(1)PROM:可编程,一次性
(2)EPROM:可擦除可编程,通过紫外线擦除
(3)EEPROM:擦除可编程,通过电子擦除
FLASH包括:(具体参见http://wjf88223.blog.163.com/blog/static/35168001201092685333808/)
(1)NOR FLASH
(2)NAND FLASH
2、存储类型与存储区关系(单片机)
data ---> 可寻址片内ram
bdata ---> 可位寻址的片内ram
idata ---> 可寻址片内ram,允许访问全部内部ram
pdata ---> 分页寻址片外ram (MOVX @R0) (256 BYTE/页)
xdata ---> 可寻址片外ram (64k 地址范围FFFFH)
code ---> 程序存储区 (64k 地址范围),对应MOVC @DPTR
3、一个C语言程序占用的内存分为以下几个部分:
(1)栈区(stack):由编译器自动分配释放,存放函数的参数值,局部变量的值等,其操作方式类似于数据结构中的栈。
(2)堆区(heap):一般由程序员分配释放,若程序员不释放,程序结束时可能由操作系统回收。
(3)全局区(静态区):全局变量和静态变量的存储位置是在一起的。初始化的全局变量和静态变量在同一块区 域,而未初始化的全局变量和未初始化的静态变量在相邻的另一块区域,程序结束后由系统自动释放。
(4)文字常量区:这一区域用于存放常量字符串,程序结束后由系统释放。
(5)程序代码区:这一区域用于存放函数体的二进制代码(ROM/FLASH)。
4、堆(heap)和栈(stack)的申请方式
stack:由系统自动分配。比如,声明在函数中的一个局部变量 int b;系统自动在栈中为b开辟空间。
heap:需要程序员自己申请,并指明大小。
在C中malloc函数;如:p1=(char *)mqlloc(10);
在C++中用new运算符;如:p2=new char[20];
注:p1,p2本身是在栈中的。
5、例子:
//main.cpp
int a = 0; //全局初始化区
char *p1; //全局未初始化区
main()
{
int b; //栈
char s[ ] = "abc"; //栈
char *p2; //栈
char *p3 = "123456"; //123456\0在常量区,p3在栈上。
static int c =0; //全局(静态)初始化区
//分配得来得10和20字节的区域就在堆区。
p1 = (char *)malloc(10);
p2 = (char *)malloc(20);
}
strcpy(p1, "123456"); //123456\0放在常量区,编译器可能会将它与p3所指向的"123456"优化成一个地方。
6、变量的存储类型和存储方式
存储类型:
存储方式:
静态存储变量通常是在变量定义时就分配一定的存储空间并一直保持不变,直至整个程序结束。
动态存储变量是在程序执行过程中,使用它时才分配存储单元,使用完毕立即释放。
静态存储变量是一直存在的,而动态存储变量则时而存在时而消失。
全局变量:作用域为整个源程序,即所有源文件;
静态全局变量:作用域为定义该变量的源文件;
把全局变量改变为静态全局变量后改变了它的作用域,而生存期不变;
局部变量:生存期为定义它的函数或复合语句;
静态局部变量:生存期为整个源程序;
把局部变量改变为静态局部变量后改变了它的生存期,而作用域不变;
**************************************************************
**************************************************************
**************************************************************
二、
对《SimpleApp中Controller/Switch绑定小实验》中出现的以下XDATA溢出错误,记录下个人的一点理解.
**************************************************************
《SimpleApp中Controller/Switch绑定小实验》中整个工程编译后的内存占用如下:
【图1】
那在函数zb_ReceiveDataIndication()中添加下面语句:
编译后的内存占用如下:
与图1相比XDATA多了6字节,个人认为这6个字节是:H E L L O \0
buf这个数组应该属于自动变量,属于动态存储方式,只有在使用它,即当buf被调用时才给它分配内存单元,开始它的生存期,调用结束,释放存储单元,结束生存期。
那在zb_ReceiveDataIndication()中这样添加(typedef __code const uint8 CCUINT8;,):
编译后的内存占用如下:
与图1相比可以发现这里字符串并没有占用XDATA,而是占用CODE。
若没有static声明为静态变量,则出现以下错误:
Error[Be009]: memory attributes not allowed on auto variables or parameters
当然,把它声明为全局变量(?常量)也可行,在SimpleController.c开头定义全局变量(?常量):
CCUINT8 buf[ ]="HELLO";
编译后的内存占用如下:
两种方式所占内存一样,全局变量与静态变量的存储方式都是静态存储,存储空间是在编译完成后就分配的,并且在程序运行的全部过程中都不会撤销。
至于出现错误Error[Be009]的原因,和实验室的人讨论也没有得出一个很明确的答案。
typedef __code const uint8 CCUINT8;
CCUINT8 buf[ ]="HELLO";
按理说应该是把HELLO\0放在常量区(???),编译后就分配内存,程序运行中只能读取不能改写。
(1)把CCUINT8 buf[ ]="HELLO";放在SimpleController.c开头声明为全局变量(?常量),这种存储方式应该是符合的;
(2)把static CCUINT8 buf[ ]="HELLO";放在zb_ReceiveDataIndication()中声明为静态局部变量(?常量),这种存储方式也应该是符合的;
(3)把CCUINT8 buf[ ]="HELLO";放在zb_ReceiveDataIndication()中,按我个人理解,编译器会认为它是一个自动变量,因为关键字“auto”可以省略,auto不写则隐含确定为“自动存储类别”,属于动态存储方式,即只有在使用它时才给它分配存储单元,开始它的生存期,使用结束后,释放单元,结束生存期。这种存储方式不符合。
对于typedef __code const uint8 CCUINT8;,我是看到协议栈中hal_adc.c定义过这么个数组:
static __code const uint16 HalAdcVddLimit[] =
{
…………
};
以及在Font.c定义过这么个数组:
__code const INT8U Font8X8[] =
{
………………
}
然后拿过来看看能否解决把字符串定义到CODE中而不占用XDATA,具体很详细的语法意思不知道,总之最终可行。
如果把这个数组定义过大,比如在SimpleController.c开头定义:
CCUINT8 buff[4000];
在zb_ReceiveDataIndication()中:
HalUARTWrite ( 0, (uint8 *)buff, sizeof(buff) );
则编译会出现以下错误:
还缺少0x219字节,即537字节,那我这样定义:CCUINT8 buff[3463];编译没有问题:
那我再加1字节:CCUINT8 buff[3464];出现这错误:
即多了0x01字节。O了~
另一种方法,自己申请一个堆
最初工程内存占用为:
那我在zb_ReceiveDataIndication()中这样添加:
编译后的内存占用如下:
与图1相比发现这样定义不占用XDATA。但个人总感觉如果废话多点,这样把字符一个一个赋进去十分麻烦,可是不知道如何快捷地把一串字符赋给动态开辟的堆……
我这样添加:
与图1相比可以看到编译后的内存占用XDATA还是多了6字节:
我这样添加:
与图1相比可以看到编译后的内存占用XDATA一样还是多了6字节:
……还是不知道怎么赋…= . =''
****************************************
小结[我不敢百分百确定,大家自己可以实验下]:
1、不占用XDATA,对于字符串:
(1) typedef __code const uint8 CCUINT8; 通过CCUINT8定义到CODE中;//char也OK
(2)通过osal_mem_alloc()函数动态开辟堆空间,把字符一个一个赋进去;用完后调用osal_mem_free()进行内存释放!
2、不占用XDATA,对于一堆需要用数组存储的数据:
通过osal_mem_alloc()函数动态开辟堆空间,把数据一个一个赋进去;用完后调用osal_mem_free()进行内存释放!
3、对XDATA溢出,我还没有试验过是否可以通过修改配置文件中的-D_XDATA_END来解决,但看了下貌似不可以,已经达到最大值8K了;
********************
// These settings are used for devices that don't use PM2/PM3
-D_IXDATA_START=E000 // The internal IXDATA block is 8K,
-D_IXDATA_END=FEFF // End of IXDATA if PM2/PM3 are not used
//
// These settings must be used for devices that use PM2/PM3.
// Note that the IXDATA_START allows the XSTACK to grow down into the non-persistent RAM, but
// checks in HAL Sleep insure that the stack is back into persistent RAM before entering PM2/PM3.
//-D_IXDATA_START=EE00 // The internal IXDATA block is 4K+,
//-D_IXDATA_END=FD55 // FD56-FEFF is used for saving the CC2430 registers before sleep.低功耗时这部分用于存储寄存器值
//
// FF00-FFFF is mapped to IDATA.
//
//
// XDATA
//
-D_XDATA_START=_IXDATA_START // The IXDATA is used as XDATA.
-D_XDATA_END=_IXDATA_END
********************
4、若CODE溢出: (1)减小程序;(2)把配置文件f8w2430.xcl/f8w2430pm.xcl中的-D_CODE_END改大点:
********************
f8w2430.xcl:
// CODE
//
// These settings determine the size/location of the ROOT segment.
// Increase _CODE_END to increase ROOT memory, i.e. for constants.
-D_CODE_START=0x0000 // Code size = 128k for CC2430-F128
-D_CODE_END=0x4000 // Last address for ROOT bank
********************
f8w2430pm.xcl:
// CODE
//
// These settings determine the size/location of the ROOT segment.
// Increase _CODE_END to increase ROOT memory, i.e. for constants.
-D_CODE_START=0x0000 // Code size = 128k for CC2430-F128
-D_CODE_END=0x29FF //(原0x28FF) Last address for ROOT bank 这里我修改增大过的。
********************
**************************************************************
**************************************************************
**************************************************************
说明:
1、本文为个人学习笔记,仅供参考.
2、错误之处还请指出,随时更新.
2、欢迎交流,转载请注明出处,谢谢!
更新:2010.12.13 ~XF 2010.12.07
关于协议栈XDATA,内存溢出的小结的更多相关文章
- Android内存溢出解决方案(OOM)
众所周知,每个Android应用程序在运行时都有一定的内存限制,限制大小一般为16MB或24MB(视平台而定).因此在开发应用时需要特别关注自身的内存使用量,而一般最耗内存量的资源,一般是图片.音频文 ...
- 《深入理解Java虚拟机》-----第2章 Java内存区域与内存溢出异常
2.1 概述 对于从事C.C++程序开发的开发人员来说,在内存管理领域,他们即是拥有最高权力的皇帝又是执行最基础工作的劳动人民——拥有每一个对象的“所有权”,又担负着每一个对象生命开始到终结的维护责任 ...
- 【JVM.1】java内存区域与内存溢出
鲁迅曾说过:Java与C++之间有一堵由内存动态分配和垃圾收集技术所围成的“高墙”,墙外面的人想进来,墙里面的人想出去. 一.虚拟机内存分布 Java虚拟机在执行Java程序的过程中会把它所管理的内存 ...
- Java之JVM调优案例分析与实战(2) - 集群间同步导致的内存溢出
环境:一个基于B/S的MIS系统,硬件为两台2个CPU.8GB内存的HP小型机,服务器是WebLogic 9.2,每台机器启动了3个WebLogic实例,构成一个6个节点的亲合式集群. 说明:由于是亲 ...
- 关于JVM内存溢出的原因分析及解决方案探讨
前言:JVM中除了程序计数器,其他的区域都有可能会发生内存溢出. 0.什么是内存溢出 当程序需要申请内存的时候,由于没有足够的内存,此时就会抛出OutOfMemoryError,这就是内存溢出. 1. ...
- JMeter内存溢出:java.lang.OutOfMemoryError: Java heap space解决方法
一.问题原因 用JMeter压测,有时候当模拟并发请求较大或者脚本运行时间较长时,JMeter会停止,报OOM(内存溢出)错误. 原因是JMeter是一个纯Java开发的工具,内存由java虚拟机JV ...
- 堆(heap)和栈(stack)、内存泄漏(memory leak)和内存溢出
来源:http://blog.itpub.net/8797129/viewspace-693648/ 简单的可以理解为:heap:是由malloc之类函数分配的空间所在地.地址是由低向高增长的.sta ...
- JVM内存溢出后服务还能运行吗
文章开篇问一个问题吧,一个java程序,如果其中一个线程发生了OOM,那进程中的其他线程还能运行吗? 接下来做实验,看看JVM的六种OOM之后程序还能不能访问. 在这里我用的是一个springboot ...
- Java 内存区域与内存溢出
内存区域 Java 虚拟机在执行 Java 程序的过程中会把他所管理的内存划分为若干个不同的数据区域.Java 虚拟机规范将 JVM 所管理的内存分为以下几个运行时数据区:程序计数器.Java 虚拟机 ...
随机推荐
- layui comfirm 监听点击确定、取消、“X”关闭按钮
layer.confirm('数据已存在,是否继续', { offset: '200px' , cancel: function (index, layero) { console.log('点击X按 ...
- POJ 3449 Geometric Shapes 判断多边形相交
题意不难理解,给出多个多边形,输出多边形间的相交情况(嵌套不算相交),思路也很容易想到.枚举每一个图形再枚举每一条边 恶心在输入输出,不过还好有sscanf(),不懂可以查看cplusplus网站 根 ...
- CRM系统不仅给企业带来更多收益而且提升销售效率
将客户信息记录在CRM系统的数据库中,同时共享沟通数据给售前.售后.SDR等上下游,客户资源还能够按照分配规则分配给适合的销售人员,帮助更快成单.全面使用CRM系统会给企业带来更多业绩. 1.全方位客 ...
- 企业实施CRM系统 创造更多利润 - Zoho CRM
对企业来说,客户关系是一种投资.我们都知道企业的资源是有限的,因此必须要将这些有限的资源投入到能够带来持续价值的客户身上.而只有良好的客户关系才能够提高客户的忠诚度,多次购买甚至溢价购买企业的产品,持 ...
- Linux alias 或者 unalias 设置别名
设置别名 查看别名:alias 设置别名: 临时设置: alias show='ls -al' 上述设置方法存在一个问题,即设置的命令别名只针对当前回话有效,一旦连接断开并重连之前设置的别名别不在有效 ...
- Elasticsearch-04-master选举
3.2 master选举机制 3.2.1 选举算法 1)bully算法 核心思想 假定所有的节点都具有一个可以比较的ID,通过比较这个ID来选举master 流程说明 节点向所有比自己ID大的节点发送 ...
- B站蹦了,关我A站什么事?
昨天的大瓜,B站蹦了,大伙都跳起来分析了一波异常原因,着实给大伙的秋招准备了一波热乎乎的素材!在大家都在关注 B站的时候, 我大A站终于要站起来了!!!经过多方网友的极力引流,我A站也蹦了- 紧急通知 ...
- RabbitMQ入门教程 [转]
1.引言 RabbitMQ--Rabbit Message Queue的简写,但不能仅仅理解其为消息队列,消息代理更合适.消息队列主要解决应用耦合,异步消息,流量削锋等问题.实现高性能,高可用,可伸缩 ...
- Grafana、Prometheus、mtail-日志监控
一:日志如何监控 在上一篇博客Grafana.Prometheus-监控平台中,简单了解了Grafana与Prometheus对项目做特定的监控打点,可视化的配置操作. 但是对于没有设置监控或者不容易 ...
- [刘阳Java]_MyBatis_其他方式来实现多表查询的操作_第9讲
MyBatis其他方式来实现多表查询的操作 利用Java中的集合框架(List,Map) 其中List存储多个查询返回的记录 Map查询返回字段,同时记录表中一条数据 <?xml version ...