关于协议栈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 虚拟机 ...
随机推荐
- 9、SpringBoot整合之SpringBoot整合SpringSecurity
SpringBoot整合SpringSecurity 一.创建项目,选择依赖 选择Spring Web.Thymeleaf即可 二.在pom文件中导入相关依赖 <!-- 导入SpringSecu ...
- Mysql:报错message from server: "Too many connections"(连接太多)
报错信息 Caused by: com.mysql.jdbc.exceptions.jdbc4.MySQLNonTransientConnectionException: Data source re ...
- Nginx:Nginx日志切割方法
Nginx的日志文件是没有切割(rotate)功能的,但是我们可以写一个脚本来自动切割日志文件. 首先我们要注意两点: 1.切割的日志文件是不重名的,所以需要我们自定义名称,一般就是时间日期做文件名. ...
- Leetcode No.167 Two Sum II - Input array is sorted(c++实现)
1. 题目 1.1 英文题目 Given an array of integers numbers that is already sorted in non-decreasing order, fi ...
- B站挂了之后出现的tengine是个啥?
一.描述 晚上刚洗漱完之后听同学说:B站挂了?woc?真挂了? 嗯!确实挂了,404的状态码,懂的都懂. 不过,最下面的tengine字眼吸引了我的注意,一时兴起,打算看看它是个什么东西,起码搞一个h ...
- 「AGC025D」 Choosing Points
「AGC025D」 Choosing Points 神仙构造题. 首先你会尝试暴力做,先随便选一个点,然后把当前能选得全选上,然后你发现这样样例都过不了. 然后我们可以这样考虑:你把距离为 \(\sq ...
- 从零学习SpringSecurity
一.简介 SpringSecurity是一个功能强大且高度可定制的身份验证和访问控制框架,和spring项目整合更加方便. 二.核心功能 认证(Authentication):指的是验证某个用户能否访 ...
- python 10篇 操作mysql
一.操作数据库 使用pip install pymysql,安装pymysql模块,使用此模块连接MySQL数据库并操作数据库. import pymysql host = 'ip地址' # 链接的主 ...
- ffmpeg入门篇-滤镜的基本使用
转发自白狼栈:查看原文 滤镜 什么是滤镜?百度百科介绍说"滤镜主要是用来实现图像的各种特殊效果......". 我们最早在ffmpeg是如何转码的一文中了解过滤镜,来回顾下当时的转 ...
- ZooKeeper 分布式锁 Curator 源码 03:可重入锁并发加锁
前言 在了解了加锁和锁重入之后,最需要了解的还是在分布式场景下或者多线程并发加锁是如何处理的? 并发加锁 先来看结果,在多线程对 /locks/lock_01 加锁时,是在后面又创建了新的临时节点. ...