分配内存失败怎么解决(附其相应的解决措施)

分配内存失败怎么解决(附其相应的解决措施)

ID:技术让梦想更伟大

在使用C语言开发嵌入式产品的过程中,当使用到malloc函数时候都会有一个争议,“使用动态内存分配安全吗?”,就连美国军方在safety-critical的嵌入式航空电子设备代码中,也禁止动态内存分配,我们来细细分析下。

C 库函数 – malloc()函数简介

当无法知道内存具体位置的时候,想要绑定真正的内存空间,就需要用到动态的分配内存,且分配的大小就是程序要求的大小。

函数的声明

用来分配所需的内存空间,并返回一个指向它的指针。

//参数:size –内存块的大小,以字节为单位//返回值:指针–指向已分配大小的内存//NULL–如果请求失败void*malloc(size_tsize)介绍一下用法#include<stdio.h>#include<string.h>#include<stdlib.h>intmain(){char*str;str=(char*)malloc(15);strcpy(str,”helloworld”);printf(“String=%s,Address=%u\n”,str,str);free(str);return(0);}

编译结果如下,大家自行体会malloc的用法。

malloc的实现机制

当我们了解了malloc的作用应用范围以及用法之后,我们先看看它是怎么实现内存分配的,在此我们需要先了解几个概念。

运行时堆

malloc内存分配原理

malloc采用推进brk指针来增加堆的有效区域来申请内存空间分配内存,维护一个内存空闲链表,当申请内存空间时,搜索内存空闲链表,找到适配的空闲内存空间,然后将空间分割成两个内存块,一个变成分配块,一个变成新的空闲块。如果没有搜索到,那么就会用sbrk()才推进brk指针来申请内存空间。

为什么避免使用

这其实要从malloc和free的设计上考虑,通常,它们是基于列表分配器算法将内存池组织到单个链表中的连续位置,使用分配器来管理该链表,实际上就是寻找空闲位置。

但是在极端的safety-critical系统中,malloc常常极其不可预测,在多核系统上进行多线程开发时是个难题,具体有以下几点。

内存有限,多次申请不易管理

嵌入式的内存就只有几十K到几百K,程序在运行时向系统申请内存使用,在使用完毕后,需要显式的释放,不然后果很严重,在多次申请复杂的逻辑开发时,这就要求程序员对动态分配的内存很了解

碎片

在c语言中的malloc进行的动态内存分配和嵌入式系统中使用到堆区的内存分配会产生内存碎片,例如

char*p;if(p=char*malloc(0)==NULL){printf(“NULL\n”);}else{printf(“NOTNULL”);}

实际上最终出现的并不是NULL,而是NOTNULL 这就说明了进行动态内存分配的时候产生了内存碎片

内部碎片的产生

假设在请求一个17字节的内存块时,它可能会获得20字节、24字节等稍大一点的字节,因此由所需的大小需要四舍五入,而产生的多余空间就叫内部碎片。

外部碎片的产生

频繁的分配与回收物理页面会导致大量的、连续且小的页面块夹杂在已分配的页面中间,就会产生外部碎片。

内存泄漏

分配出去的内存在使用之后没有释放掉,没有回收,长此以往,会造成没有足够的内存可以分配。一般表现为运行时间越长,占用的内存越多,最终导致系统奔溃。

所以在进行硬件内存比较小的外围开发的时候,一定要避免内存泄漏,合理的使用内存空间,才能更好的发挥硬件的作用。

怎么解决

在继续使用malloc和free的情况下

正确使用malloc函数分配内存

在实际应用中,我们可以试着把连续的大块内存按分区来管理。每个分区中包含整数个大小相同的内存块。如图所示:

利用这种机制,就可以得到和释放固定大小的内存块。这样内存的申请和释放函数的执行时间就是确定的了,但是特定的内存块在释放时,必须重新回到它原本属于的内存分区。

正确使用free函数释放内存

自定义一套内存分配器

尽量避免使用malloc时,我们可以自定义一套本地线程内存分配器,基于栈的分配器,以及基于本地线程的分配器,通过为每个线程分配特定的内存池来避免冲突

最后

在嵌入式系统中,并不是说不使用malloc()和free()管理内存,而是说在使用时需要让我们的代码更具预测性,避免不必要的未知bug产生。

猜你喜欢

Protobuf:一种更小、更快、更高效的协议

在SMT32程序HEX文件中加入固件版本信息

发表评论

登录后才能评论