如何确保不使用动态内存

  在许多嵌入式应用程序中,内存分配必须是静态的,而不是动态的。意味着在应用程序中不应使用对malloc()或free()等内容的调用,因为它们可能会在运行时失败(内存不足、堆碎片)。

  但是,当与第三方库甚至 C/C++ 标准库链接时,如何确保不使用动态内存?对于C++对象或对 printf()的简单调用,也可能会出现此问题,该调用需要在内部分配一些动态内存。

1、零堆大小?

  一种简单(而且相当幼稚)的方法是将堆大小设置为零。大多数链接器脚本或链接器环境都能够将堆大小设置为零,如下所示:

  但是,这无济于事,因为大多数链接器脚本只使用堆栈空间和变量 (bss) 之间的可用空间: 因此,将堆大小设置为零只是假设保留为零,但库的 _sbrk()将继续使用动态内存,可能会崩溃到堆栈空间。

  底线:大多数链接器脚本堆大小设置为零将无济于事。它甚至增加了堆崩溃到堆栈中的可能性,因为链接器假定堆的使用量为零。但它不会阻止使用堆。

2、堆在链接器文件中

  这可以从下面显示的链接器文件中看出:

  若要确保不使用堆,最简单的方法是简单地删除上述链接器文件中的 .heap 分配。检查链接器文件中是否有“堆”或类似内容,并确保没有为其分配内存。特别是确保没有使用符号“__prvHeapStart”或“__prvHeapLimit”,因为它们通常是newlib/newlib-nano库动态内存分配所必需的。

3、链接器自由标记脚本

  恩智浦MCUXpresso IDE等某些环境正在使用自动生成的链接器文件。但是,如果您了解它使用的FreeMarker脚本,则很容易处理此问题。脚本位于

<MCUXpresso IDE Installation Path>\ide\Wizards\linker

  所以我可以使用修改后的 FreeMarker 脚本轻松禁用 .heap:

4、__sbrk()

  删除堆及其符号后,malloc()的任何用法都应该给出一个链接器错误,类似于这个错误:

Invoking: MCU Linker
arm-none-eabi-gcc -nostdlib -Xlinker -Map="AEMBS_tinyK22_HS22.map" -Xlinker --gc-sections -Xlinker -print-memory-usage -Xlinker --sort-section=alignment -Xlinker --cref -mcpu=cortex-m4 -mfpu=fpv4-sp-d16 -mfloat-abi=hard -mthumb -T "AEMBS_tinyK22_HS22_Debug.ld" -o "AEMBS_tinyK22_HS22.axf" ./utilities/fsl_assert.o ...  ./McuLib/FreeRTOS/FreeRTOShooks.o   
arm-none-eabi/bin/ld.exe: arm-none-eabi/lib/thumb/v7e-m+fp/hard\libcr_newlib_semihost.a(_cr_sbrk.o): in function `_sbrk':
_cr_sbrk.c:(.text._sbrk+0x38): undefined reference to `_pvHeapStart'

5、链接器交叉引用

  如果不清楚使用内存分配或导致错误的原因,可以使用链接器交叉引用。为此,必须将 GNU 链接器 –cref 选项添加到链接器选项中:

  这会在链接器 .map 文件中生成如下所示的信息:

Cross Reference Table

Symbol                                            File
ADC0_DriverIRQHandler                             ./startup/startup_mk22f51212.o
ADC0_IRQHandler                                   ./startup/startup_mk22f51212.o
ADC16_ClearStatusFlags                            ./drivers/fsl_adc16.o
ADC16_Deinit                                      ./drivers/fsl_adc16.o
...
main                                              ./source/main.o
                                                  ./startup/startup_mk22f51212.o
malloc                                            arm-none-eabi/lib/thumb/v7e-m+fp/hard\libc_nano.a(lib_a-malloc.o)
                                                  arm-none-eabi/lib/thumb/v7e-m+fp/hard\libc_nano.a(lib_a-rand.o)
                                                  ./drivers/fsl_common.o
mcgConfig_BOARD_BootClockRUN                      ./board/clock_config.o

  这给出了使用 malloc()之类的模块列表。

6、图像信息

  找出依赖关系的另一种方法是在 Eclipse/MCUXpresso 中使用“图像信息”视图,请参阅在构建后操作中列出具有 GNU 大小实用程序的所有文件的代码和数据大小:

7、免费实时操作系统静态内存分配

  更多旁注:默认情况下,FreeRTOS 使用自己的动态堆分配。但是可以静态方式运行 RTOS(无动态内存分配),请参阅带静态内存分配的 FreeRTOS V9.0.0。

8、总结

  许多应用程序不需要动态内存分配和使用。为了防止使用 malloc()和 free(),最好删除链接器文件中的任何堆定义,以导致链接器错误。那么 GNU 链接器交叉引用表或图像信息可能非常有用。

9、链接

  • 使用 FreeMarker 脚本的示例:教程:将 BLE+NRF Kinetis Design Studio Project 移植到 MCUXpresso IDE
  • 带有 FreeMarker 脚本的引导加载程序:将引导加载程序应用程序与 Eclipse 和 FreeMarker 脚本链接起来
  • 自由标记脚本:https://freemarker.apache.org/

欢迎关注:

posted @ 2022-12-18 08:47  Moonan  阅读(182)  评论(0编辑  收藏  举报