Memory Management.docx
- 文档编号:3892214
- 上传时间:2022-11-26
- 格式:DOCX
- 页数:11
- 大小:50.16KB
Memory Management.docx
《Memory Management.docx》由会员分享,可在线阅读,更多相关《Memory Management.docx(11页珍藏版)》请在冰豆网上搜索。
MemoryManagement
MemoryManagement
Forallproject
HISTORY
PreparedBy.
IssueDate
Rev.
Description
Remark
Allen
2011/06/01
PA1
介绍多线程下的内存模型和使用内存中容易出错的地方
●Firstrelease
●
●
●
●
●
目录
目錄3
1.簡介4
1.1.文檔使用者4
1.2.參考4
1.3.縮略詞4
1.4.問題報告4
1.5.內存模型4
1.6.內存管理原則6
1.6.1.檢查內存泄漏7
1.6.2.檢查內存重復釋放7
1.6.3.檢查內存越界7
1.6.4.避免在棧中分配過大內存8
1.6.5.注意對指針的使用9
1.6.6.多線程模式下的內存問題10
1.6.7.理解幷遵守平臺(如obigo,OP,BREW)的內存使用原則11
1.简介
1.1.文檔使用者
1.2.参考
本文参考了如下的文档,各个参考文档使用[x]来标记。
1.3.缩略词
1.4.问题报告
有任何关于此文档的问题,请报告给allenq@。
内存和指针的使用和管理是c开发大型项目最重要的内容之一。
不少大型项目的失败都是大量的内存和指针使用不当引起。
下面介绍多线程ui情况下内存模型和使用注意事项。
1.5.内存模型
目前嵌入式的线程模型是单进程多线程的模式。
在这种模式下,内存模式如下
内存分为四大类
●代码段,放置所有的代码
●全局数据段放置全局数据和静态数据,所有线程共享全局数据段
●堆,放置动态分配的内存,所有线程共享堆
●栈,放置线程的局部变量,不同线程有不同的栈
intg_var1;
char*g_var3;
func1()
{
staticdoubles_cc=0;
intf1_var1;
char*f1_var2=malloc(10);
func2();
}
func2()
{
charf2_var2;
f2_var2++;
g_var3=malloc(10);
}
假定当前有两个task,task1&task2
task1调用func1并且运行到了func2的g_var3=malloc(10)代码处
task2调用func1并且运行到了func1的char*f1_var2=malloc(10);函数处
此时,线程模型如下图
1.6.内存管理原则
内存引起的bug,特定如下
1不会马上引起错误,但以后不确定的某种情况下可能发生错误,而且该错误与诱发错误的地方几乎看不出任何联系
2一旦发生错误,都是致命错误,导致系统crash
3debug非常麻烦
所以”内存使用不当”是用c/c++开发大型项目中最重要的bug之一,尤其经验不是非常丰富的工程师,最容易犯这类错误(其实经验比较丰富的工程师也会犯这类错误)。
如果相当一部分工程师不注意内存使用,在很多地方写的代码都有内存错误,但这些错误只在特定条件下爆发,因此最初从表面上看,系统运行还算正常。
但当这些错误累加到一定程度,对系统的危害是非常大的。
因此建议所有的工程师都重视内存使用,养成内存检查的习惯
建议每写完/修改完一个函数,都按照以下流程检查错误
1.6.1.检查内存泄漏
内存泄漏就是,对于动态分配的内存,没有释放
如果写了以下代码
char*pStr=mfw_alloc(10)
mfwHndtim=timCreate();
对应在函数结束前,就应该释放内存
mfw_free(pStr,10)
timDelete(tim)
1.6.2.检查内存重复释放
对已经释放的内存再次释放,就是重复释放
如
char*pStr=mfw_alloc(10)
…..
mfw_free(pStr,10)
…….
mfw_free(pStr,10)//内存重复释放,可能造成内存错误
1.6.3.检查内存越界
3.1避免数组越界
如intnNum[10]
要确认各种情况下,不可以访问内存nNum[n]n>=10
比较良好的习惯是用宏来防治越界
如#defineMAX_NUM10
intnNum[MAX_NUM]
for(intI=0;I { 访问nNum; } 3.2避免字符串越界 ●理解c语言中字符串以’\0’(真0)结束,如果一个字符串中最大容纳10的字符,需要分配11个字符长度,如charcStr[MAX_LEN+1],最后一个字符放置’\0’ ●分配字符串后,需要立刻把字符串置0 如charcStr[MAX_LEN+1]; memset(cStr,0,MAX_LEN+1) 否则,请看以下代码 如charcStr[MAX_LEN+1]; inta=strlen(cStr); 此时a的数值不确定,很有可能大于MAX_LEN+1,如果在用a对cStr操作,后果非常严重 ●理解所有字符操作函数,都是以’\0’为结束,如 chara[10]={'1','2','3','\0','4'}; 此时数组中的内容为 31323300340000000000 ⏹此时如果调用strlen(a),返回值为3,因为第四个字符为’\0’,第五个字符不予处理 ⏹如果执行以下语句 charb[10], memset(b,0,10) strcpy(b,a); 此时b的内容为31323300340000000000,即只copy到a的第三个字符 ⏹如果执行以下语句 charc[10]={'1','2'}; strcat(ca); 此时c的内容为31323132330000000000 1.6.4.避免在栈中分配过大内存 我们开发的嵌入式软件,每个task的栈的大小都非常有限(目前mmitask的栈为6k). 栈的使用有以下特点。 ●栈有迭加效果, 如 函数a在栈中分配了1k字节内存 函数b在栈中分配了1k字节内存 函数c在栈中分配了1k字节内存 只调用a|b|c都没有问题,但如果a调用b,b调用c,就可能出错 ●一旦出错,非常非常难查 函数中的局部变量分配在栈中,一般来讲,如果一个局部变量大于100个字节,就应该动态分配 错误写法 intfunc1() { charb[100]//b占用100个字节的栈空间,可能诱发栈被破坏 } 正确写法 intfunc1() { char*b=mfw_alloc(100); } 1.6.5.注意对指针的使用 对指针的使用规则如下 ●初始化为0 ●分配一块空间,指针指向该空间 ●释放空间,指针重新指向0 代码事例 ●初始化 char*pStr=0; ●分配空间 if(pStr==0)//pStr为0,表示其不指向任何动态内存,不要释放 pStr=mfwAlloc(10) ●释放空间 if(pStr! =0)//pStr不为0,表示其指向动态内存,需要释放 { mfwFree(pStr); pStr=0; } 这样我们可以掌握以下原则 ●如果某指针为0,则该指针不指向任何动态分配内存。 ⏹可以分配内存同时把首地址给该指针,而不会内存泄漏。 ⏹如果该指针指向某动态分配内存,释放后该指针指向0,以后不需要再释放内存,防止内存重复释放 ●如果某指针不为0,说明该指针指向动态分配内存 ⏹如果需要分配内存同时把首地址给该指针,需要先释放该指针指向的原内存,否则会内存泄漏 ⏹在离开该指针作用范围前,需要释放该指针指向的动态内存 1.6.6.多线程模式下的内存问题 下面举一个简单的例子说明线程同步, 对于线程不是很了解的同仁,建议还是读读其它相关数据,至少要理解相关基本概念,如线程和程序的关系等。 inttmp=0; chartmpChar[10]; voidfunc1() { for(tmp=0;tmp<10;tmp++) tmpChar[tmp]=tmp; } voidfunc2() { …… tmp=20; …… } ●如果这两个函数在同一个task里顺序执行,不会有问题 ●假定func1由task1执行,func2由task2执行.如果func1先被运行,在运行到一半时(如tmp=5时),task1被中断,task2运行,给tmp赋值为20.然后task2休眠,task1接着运行,此时tmp=20,执行以下语句而内存越界 tmpChar[20]=20 这样的问题是比较难查的,可能大多数情况下task1和task2不会互相干扰,只是在特殊情况下才出现问题. 除了全局变量,凡是对所有线程都可见的存储空间(如堆内存和静态变量),都有上述问题。 请采取以下措施,避免多线程编程模式下的内存问题 ●尽量避免使用全局变量和静态变量 ●如果必须使用全局变量和静态变量,并且该全局变量和静态变量有可能被不同的线程访问,要用信号量等操作系统机制保护 ●如果使用回调的方式实现功能,尽量在回调里面发送消息给另外一个线程,另外一个线程收到消息后实现该功能,而不要直接在回调函数里面写功能实现代码。 如线程A向线程B注册了一个回调函数,希望线程B发生特定事件后回调该函数实现某编码功能。 则最好不要在该回调函数里面实现编码功能,回调函数应该只是向线程A发送一个消息,线程A收到该消息后实现编码功能 1.6.7.理解幷遵守平台的内存使用原则 平台本身一般不会发生内存错误(否则该平台不会广泛使用),一般是我们对平台理解的不够透彻导致。 这样做看似比较麻烦,但是熟悉以后,其实非常快的。 同时基本把内存错误都避免了。 1.7.Referencecode #include intfunc1() { intd; printf("dddddddd"); scanf("%d",&d); return0; } intfunc2(); #include #include typedefint(*func)(); voidmem_override() { intarr[10]; memset(arr,0,sizeof(int)*10); arr[10]=3; return; } voidstr_len_test() { intstrLen=0; { charcStr[10+1]; strLen=strlen(cStr); //ifyoucallstrcpy(cStr,str1,strLen);willmemoryoverride memset(cStr,0,10+1); strLen=strlen(cStr); } { chara[10]={'1','2','3','\0','4'}; charb[10]; charc[10]={'1','2'}; strLen=strlen(a); memset(b,0,10); strcpy(b,a); strcat(c,a); } return; } voidstack_override() { inttmp[10000000]; return; } voidmain() { stack_override(); return; }
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- Memory Management