【ESP32】带 log 记录的 malloc 动态申请内存,用于debug 调试查找报错原因

本文章以ESP32为依托,旨在解决在【嵌入式工程】开发过程中,在动态申请内存这部分,由于 malloc 之后,忘记 free 释放,造成内存溢出导致 MCU重启的问题

image-20230911133724204

📋 个人简介

  • 💖 作者简介:大家好,我是喜欢记录零碎知识点的菜鸟打工人。😎
  • 📝 个人主页:欢迎访问我的 Ethernet_Comm 博客主页🔥
  • 🎉 支持我:点赞👍+收藏⭐️+留言📝
  • 📣 系列专栏:物联网开发ESP32 🍁
  • 💬格言:写文档啊不是写文章,重要的还是直白!🔥

image-20230911133730620

1. 模拟 malloc 不 free 的现象

场景:在 main函数中只申请内存,不释放内存,并监控内存剩余量

现象:内存申请完毕后,MCU 就重启了

#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/event_groups.h"
#include "nvs_flash.h"

void app_main(void)
{
    esp_err_t err = nvs_flash_init();
    if (err == ESP_ERR_NVS_NO_FREE_PAGES || err == ESP_ERR_NVS_NEW_VERSION_FOUND) {
        ESP_ERROR_CHECK(nvs_flash_erase());
        err = nvs_flash_init();
        printf("nvs_flash_init");
    }
    char *queue;

    while (1){
        queue = malloc(10000);
        queue[0] = 12;
        vTaskDelay( 100 / portTICK_PERIOD_MS);
        ESP_LOGI("app_main:test malloc not free", "[APP] Free memory: %d bytes", esp_get_free_heap_size());
    }      
 
}

请添加图片描述
image-20230913150250289

若在 malloc 之后及时free,则没有问题

image-20230913150406696

但是再有经验的人也会有犯错误的时候。

2. 带 log 记录的 malloc 方式

参考:嵌入式开发正确使用动态内存的方法

正确使用动态分配内存

调试过程中发现

在此基础上,自己增加了以下内容

  • _dmem_log 结构体增加 funcName ,用于记录动态分配内存的函数名称

  • log 日志数组初始化

  • MallocExt()函数接口增加 fun 参数

  • MallocExt()失败时,增加打印 log 日志记录的功能

2.1 功能描述

#define DMEM_DBG 1 打开debug调试开关

  • 当关闭 debug 开关时,MallocExt()FreeExt() 函数与 malloc()free() 是等价的
  • 当打开 debug 开关时,开启malloc 日志记录功能
  1. 定义一个结构体数组 s_astDMemLogp[20] 用于存储每一次 malloc 分配的信息,主要包含 分配的大小和函数名
  2. 在 debug 模式下,MallocExt() 都会调用 LogDMem()记录malloc的信息
  3. 当内存不够用时,则 malloc 失败,则会打印 上20次 malloc 的信息用于查找问题出现的原因

2.2 只申请不释放,申请失败时会打印 log 数组中的信息

只申请不释放,申请失败时会打印 log 数组中的信息

测试代码:

#include <stdio.h>
 
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/event_groups.h"
#include "nvs_flash.h"
#include "esp_vfs_fat.h"

#include "debug.h"
 
void test_func1()
{
    char *queue;
    queue =  MallocExt (11111,"test_func1");
}
 
void test_func2()
{
    char *queue;
    queue =  MallocExt (22222,"test_func2");
} 
 
void app_main(void)
{
    esp_err_t err = nvs_flash_init();
    if (err == ESP_ERR_NVS_NO_FREE_PAGES || err == ESP_ERR_NVS_NEW_VERSION_FOUND) {
        ESP_ERROR_CHECK(nvs_flash_erase());
        err = nvs_flash_init();
        printf("nvs_flash_init");
    }
    char *queue;

    while (1)
    {
        queue =  MallocExt (10000,"app_main");
        queue[0] = 12;
        test_func1();
        test_func2();
        //FreeExt(queue);
        vTaskDelay( 500 / portTICK_PERIOD_MS);
        ESP_LOGI("app_main:test malloc not free", "[APP] Free memory: %d bytes", esp_get_free_heap_size());
    }      
}

image-20230913154437732

2.3 申请后及时释放,不报错误

image-20230913160821564

3. 代码展示

代码请到 csdn 下载

没有积分的同学,请点赞收藏,私信留言

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
malloc 是 C 语言中的一个函数,它用于在程序运行时动态申请内存malloc 函数的实现机制是在堆(heap)中分配一段连续的内存空间,并返回指向该内存空间的指针。 堆是一种动态内存分配机制,它是指在程序运行过程中动态分配的内存空间。堆内存空间的大小可以在程序运行时动态调整,因此堆内存空间的大小是不确定的。 动态内存分配和静态内存分配所占的内存区是不同的。静态内存分配是在程序编译时就确定了内存空间的大小和位置,它所占用的内存区是静态数据区。而动态内存分配是在程序运行时才分配内存空间,并且所占用的内存区是堆(heap)。 堆是由操作系统维护的,它的大小是动态变化的。当我们使用 malloc 函数申请内存时,操作系统会在堆中分配一段连续的内存空间,并返回指向该内存空间的指针。malloc 函数会在堆中查找一段足够大的连续空间,如果找到了就将这段空间分配给程序使用,如果找不到就会返回 NULL。 由于动态内存分配是在程序运行时才进行的,因此需要程序员自己管理和释放所申请内存空间。如果程序员没有正确地管理和释放内存空间,就会导致内存泄漏等问题。 总之,malloc 函数是通过在堆(heap)中分配一段连续的内存空间来实现动态内存分配的,而静态内存分配所占用的内存区是静态数据区。动态内存分配需要程序员自己管理和释放内存空间。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

积跬步、至千里

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值