0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

单片机上用malloc()是个坑,有隐患?

无际单片机编程 来源:无际单片机编程 2024-02-22 15:53 次阅读

单片机研发前几年,一直没用过动态内存分配的功能,但是如果想成为软件架构设计师,这是绕不过的一道坎。

其实单片机很少使用c标准库自带的malloc()函数去动态分配内存,除非,你看老板不爽...

因为有缺陷,文章后面会提及。

一般是工程师借助现成的参考代码,然后重新设计内存管理代码,改进动态内存分配算法

不过代码难度挺大,c语言功底不好的,看到代码会失声痛哭....

不信?我装个逼给你看!

下图,是以前自己借鉴(抄袭),再吃透,后改进的内存管理代码,测试已解决内存碎片问题。

43ddafca-d157-11ee-a297-92fbcf53809c.png

43f53000-d157-11ee-a297-92fbcf53809c.png

代码没多少,却让我充分感受到,编程语言只是工具,编程思维才是灵魂

本来是计划用在无际单片机特训营项目6的,但是感觉太复杂了,怕老铁们学着学着来骂我,所以这代码就失宠了。

新手,或者有些一直从事比较简单产品工程师,可能无法理解,malloc的应用场景,到底在哪里?

我以无际单片机特训营项目3来举例几个使用场景,或许你就明白了。

1.malloc使用场景1:动态任务创建

学过我们项目3的老铁,不知道有没有发现一个问题。

在用我们那个"小系统"创建任务的时候,不够灵活,每次增加新的任务,要手动在头文件增加任务ID

441628d2-d157-11ee-a297-92fbcf53809c.png

这样做的目的,是为了给下面这个任务结构体数组OS_Task,分配固定的内存空间。

44257da0-d157-11ee-a297-92fbcf53809c.png

最后才是创建任务。

44347c74-d157-11ee-a297-92fbcf53809c.png

如果使用动态内存分配,就可以省略前面步骤,直接创建任务,在任务创建函数里通过动态内存分配函数,给任务动态开辟一块内存,如果对RTOS有研究,应该知道我在讲什么..

2.malloc使用场景2:探测器列表

项目3是需要和不同的探测器(遥控器、门磁探测器、红外探测器、烟雾探测器等等)组网使用的。

我们做了一个菜单,在OLED屏上显示已经组网的探测器列表。

44428d14-d157-11ee-a297-92fbcf53809c.png

每个主机,已经组网的探测器数量都不一样,有些主机最多支持组网255个探测器。

每个探测器都有探测器ID、组网标志、序号、名称等参数

44562c48-d157-11ee-a297-92fbcf53809c.png

那是不是意味着,如果主机最大支持255个探测器,如果没有动态内存分配,就要提前定义能够存储255个探测器参数的结构体数组?

事实上,我想到两种方式。

第一种是先存到外部的flash里,用到了再读出来,程序操作起来麻烦,而且效率慢,优点是省RAM

第二种是直接分配255个探测器的静态存储空间,程序操作爽,效率高,但费RAM,还好特么用了STM32

我这个探测器列表菜单,用的是第二种方式,因为我主机对探测器数量的上限设置是20个,哈哈。

446149b6-d157-11ee-a297-92fbcf53809c.png

对于这种功能需求,王炸的解决方案,就是用动态内存分配了!用时分配,用完释放!

但是,不建议直接用malloc()!!!

其实我第一次接触内存管理,是做蓝牙产品,用TI协议栈的时候。

当时有点奇怪的是,c语言标准库有malloc()动态内存分配和free()内存释放函数,osal系统为什么要自己写osal_mem_alloc()和osal_mem_free()?

直到后面自己做了一些复杂点的项目,自己也调过内存管理代码,才理解。

单片机上用malloc(),是个坑,有隐患。

我觉得内存碎片,是万恶之源。

malloc()函数本身只是动态分配内存,并没有直接解决内存碎片问题。

什么是内存碎片?

刚开始,我也不理解,什么是内存碎片,网上搜了很多相关内容,越绕越晕。

我尝试用通俗易懂的语言,长话短说,能不能理解,看基础和悟性了。

内存碎片分为两种:

1.外部碎片

想象一下,有一个大型的图书馆,图书馆的书架上摆满了各种各样的书籍,这些书籍大小可能不一样,书籍就像内存中的内存块(已被动态分配的内存),书架上的空位代表空闲内存(未被分配的内存或者被释放的内存)。

当读者借阅书籍后,书架上会留下一些空位。随着时间的推移,这些空位可能变得非常分散,就像散落在书架上的小块空间。

如果突然要存放一本很大很厚的书,到书架上时,可能很难找到足够大的连续空位来放置这本书。

那如果往后要存放的书,都是很大很厚的呢?

是不是虽然空位很多,但就是放不进去?那这块空间是不是就浪费掉了?

在内存分配时也是同理,如果频繁地用malloc()分配很多零散的内存块,每个内存块占用的字节数都不一样。

当这些内存块使用完,被free()释放以后,这块空闲内存,比如是8个字节,那下次,再有动态分配内存需求时,除非是8个字节或者以下才能使用这个内存块,如果是8个字节以上,这块内存块就相当于一直用不上,就浪费了。

所以说,即使总的空闲空间足够,但由于碎片化,也不好满足大内存块的分配请求。

这就是,在内存管理中,外部内存碎片化会导致系统无法为新的内存请求,分配足够的连续内存空间注意连续内存空间很重要,如果不连续,处理器就要不断从整个内存池去寻找,这样读取效率就会变低,这是内存碎片的影响。

2.内部碎片

内部内部碎片就是分配了内存空间,但未被使用的部分。

为此,我做了一个实验:

446f9796-d157-11ee-a297-92fbcf53809c.png

上图程序里,我给p1和p2分配1个字节内存,实际却分配了8个字节的空间,在释放前这7个字节都不能再被分配,相当于7个字节空间就浪费了。

以上两种碎片的产生,会让程序产生一种很尴尬的现象,就是明明有很多空闲内存,但总是分配失败,甚至导致程序死机,而且这种死机现象,通常是没有规律的。

印象中,我以前解决碎片问题的方法,大概是,内存释放后,把该内存块后面所有已分配的内存块往前迁移。

447a7bf2-d157-11ee-a297-92fbcf53809c.png

其实内存管理,就是开辟一个很大的数组,称内存池

449fd1fe-d157-11ee-a297-92fbcf53809c.png

然后后面所有的功能,比如动态内存分配,内存释放,都是基于这个大数组去完成,会涉及到数据结构,涉及到算法。

所以,数据结构和算法,这个时候针对性去学是最合适的

很多人项目都没做过,就去学,没什么鸟用,学完也不知道能干嘛。

说到这里,我相信你应该没有单片机上用malloc()的勇气了吧?

小批量生产可能测不出来,大批量生产就会陆续出现死机现象了,碰到了,就偷偷躲厕所里哭吧,这种问题能找死个人!

至于很多人说的,比如单片机不用malloc(),是因为内存资源有限,个人人为不是问题本质,一般能用上动态内存分配的产品,单片机内存资源都比较大。

本质就是用malloc()容易产生内存碎片,从而会引发一系列的问题,比如数据读取效率问题、稳定性问题等等...

PC上用malloc()估计也会存在内存碎片的问题,只是电脑内存动不动就上G,没有嵌入式设备这么敏感,当然PC可能还有别的方式去解决碎片化问题,这块我没做过,不做表态。





审核编辑:刘清

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 单片机
    +关注

    关注

    6036

    文章

    44557

    浏览量

    634812
  • 探测器
    +关注

    关注

    14

    文章

    2634

    浏览量

    73008
  • C语言
    +关注

    关注

    180

    文章

    7604

    浏览量

    136729
  • OLED屏
    +关注

    关注

    0

    文章

    162

    浏览量

    20846
  • malloc
    +关注

    关注

    0

    文章

    52

    浏览量

    73

原文标题:为什么单片机上的程序不建议使用malloc?

文章出处:【微信号:nanshuqg,微信公众号:无际单片机编程】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    浅谈 malloc 函数在单片机上的应用

    聊聊 malloc函数 在单片机程序设计中怎么使用
    的头像 发表于 05-18 09:35 2324次阅读
    浅谈 <b class='flag-5'>malloc</b> 函数在<b class='flag-5'>单片机上</b>的应用

    为什么在单片机上的程序不怎么使用malloc,而PC上经常使用?

    一样跑在硬件上的,它们属于一层次的。过去之所以没有区分出单片机上的程序和PC机上的程序的一些差异,就是没有弄明白这一点。由此,以前的一些疑惑也就解开了。为什么在单片机上的程序不怎么使
    发表于 05-03 13:33

    请问TTL烧录编程,单片机上要找哪五

    TTL烧录编程,单片机上要找哪五
    发表于 01-24 20:27

    如何在单片机上也可正常使用动态内存分配

    51单片机内存动态分配序言最近玩51单片机碰到一问题,51中malloc函数并不能像在PC上一样正常运行,这涉及到了内存池的概念。下面就来演示一下如何在
    发表于 11-19 07:36

    malloc的相关资料分享

    首先,malloc( )属于标准C语言函数,当然可以在单片机上使用,如STM32可以先在启动文件中设置heap的大小,再使用动态内存分配: Heap_Size EQU 0x00000200 \\也就
    发表于 11-26 08:27

    如何在单片机上摁键编辑信息可以在单片机上显示?

    做一设计求指导,就是想在单片机上摁键编辑信息可以在单片机上显示,并且能发送到电脑上,还能收到电脑的的信息。
    发表于 09-28 06:37

    32单片机上的uCOSII和FreeRTOS两实时操作系统什么区别?

    32单片机上的uCOSII和FreeRTOS两实时操作系统什么区别啊,在上班之后一般是的哪一类实时操作系统比较多啊
    发表于 10-27 08:07

    Atmel AVR 单片机上网方案

    Atmel AVR 单片机上网方案
    发表于 01-14 15:04 6次下载

    浅谈单片机上电复位后端口的状态

    量避免处于输出状态(无论是输出低还是输出高) 为什么要这样说呢?因为单片机外围电路的动作就是靠单片机端口输出低电平或者高电平来控制的。假如单片机端口一上电就处于输出高或者低电平的状态,那么很容易出现误动作。例如,
    的头像 发表于 11-30 18:17 4105次阅读

    分享可应用于单片机的内存管理模块mem_malloc

    空间不足而分配失败,从而导致系统崩溃,因此应该慎用,或者自己实现内存管理。 mem_malloc就是一不会产生内存碎片的、适合单片机使用的内存管理模块。
    的头像 发表于 06-25 08:54 3023次阅读
    分享可应用于<b class='flag-5'>单片机</b>的内存管理模块mem_<b class='flag-5'>malloc</b>

    关于stm32 MCU申请动态内存malloc的认识

    首先,malloc( )属于标准C语言函数,当然可以在单片机上使用,如STM32可以先在启动文件中设置heap的大小,再使用动态内存分配: Heap_Size EQU 0x00000200 \\也就
    发表于 11-18 16:21 14次下载
    关于stm32 MCU申请动态内存<b class='flag-5'>malloc</b>的认识

    记录单片机使用malloc产生内存泄露的问题及解决方法

    项目场景:单片机使用malloc产生内存泄露的问题问题描述:bug1:创建了一结构体指针,通过malloc动态开辟内存的方式开辟了一段内存空间,然后进行写入数据修改数据的操作,但是下
    发表于 12-03 10:21 8次下载
    记录<b class='flag-5'>单片机</b>使用<b class='flag-5'>malloc</b>产生内存泄露的问题及解决方法

    89系列单片机上机指导

    89系列单片机上机指导
    发表于 06-13 14:20 2次下载

    如何在单片机中使用malloc函数

    但是每个嵌入式 RTOS 都会有自己的内存管理方式,本文就来聊聊我对 malloc 函数在单片机程序设计中的一些看法。 本文并不是要说明在单片机中怎么使用 malloc函数,而是
    的头像 发表于 04-24 09:50 2553次阅读
    如何在<b class='flag-5'>单片机</b>中使用<b class='flag-5'>malloc</b>函数

    如何实现一malloc

    任何一用过或学过C的人对malloc都不会陌生。大家都知道malloc可以分配一段连续的内存空间,并且在不再使用时可以通过free释放掉。但是,许多程序员对malloc背后的事情并不
    的头像 发表于 11-13 14:31 779次阅读
    如何实现一<b class='flag-5'>个</b><b class='flag-5'>malloc</b>