RT-Thread 堆区大小设置
一、利用栈区的空间作为堆区
看过我之前的笔记的小伙伴都知道,以前我是通过申请栈区的空间使用的,感兴趣的小伙伴可以看我之前的笔记,RT-Thread移植到stm32。
在board.c文件文件中的代码如下所示:
#if defined(RT_USING_USER_MAIN) && defined(RT_USING_HEAP)
#define RT_HEAP_SIZE 1024
static uint32_t rt_heap[RT_HEAP_SIZE]; // heap default size: 4K(1024 * 4)
RT_WEAK void *rt_heap_begin_get(void)
{
return rt_heap;
}
RT_WEAK void *rt_heap_end_get(void)
{
return rt_heap + RT_HEAP_SIZE;
}
#endif
从上面的代码中可以看出,申请了一个栈空间rt_heap数组,大小为4K。但是这样在使用RT-Thread堆内存的时候就不太友好了。缺点如下:
堆内存大小是固定的,使得RT-Thread系统没有最大化的利用STM32的内存空间。
在RT-Thread的堆内存中使用了相应的内存算法,容易造成内存碎片化。,所以应将栈剩余的空间全部用于堆内存使用,有关算法可以看RT-Thread内存管理。
发生堆栈溢出的时候,不利于问题的查找。
所以我们使用的时候,应该获取堆区与栈区的内存分界地址,以便于给RT-Thread的堆内存使用。
二、STM32内存知识
在获取堆内存与栈内存之前,我们需要简单的理解STM32的内存知识,如果想了解更详细的内容,可以看我之前的笔记,STM32内存知识。
- code:代码存储区,存放函数体的二进制代码
- Ro-data:只读数据存储区,存放字常量数据类型(如const类型)程序结束后有系统自动释放
- RW-data:初始化可读写变量的大小,程序结束后由系统自动释放。
- ZI-data:没有初始化的可读写变量大小,程序结束后由系统自动释放。
- heap:堆区,一般由程序员分配释放,若程序员不释放,程序结束时可能由OS释放。
- stack:栈区,由编译器自动分配释放,存放函数的参数值,局部变量的值等。
- RO Size:包含Code及RO Data,表示只读数据占用Flash空间的大小。
- RW Size:包含RW Data及ZI Data,表示运行时占用的RAM的大小。
- ROM Size包含Code,RO Data及RW Data,表示烧写程序所占用的Flash的大小。
STM32程序运行的流程。如下图所示:

栈向下生长,内存地址由高至低;堆向上,内存地址由低至高,堆栈之间没有固定的界限,如下图所示:

从上面两点可以看出来,RAM是包含堆区和栈区,而堆区与栈区没有明确的界限,所以内存中没有使用的栈空间都可以申请为堆内存。我们只需要找出栈空间接结束地址,也是ZI段和结束地址即可。
三、获取栈空间的结束地址
因为不同编译器的内存标识不一样,所以需要注意一下不同环境下的获取方式。
MDK环境下,栈结束地址的获取,如下所示:
extern unsigned char Image$$ER_IROM1$$Limit; // 获取RW段在FLASH中的加载地址
extern unsigned char Image$$RW_IRAM1$$Base; // 获取RW段在RAM中的运行地址
extern unsigned char Image$$RW_IRAM1$$RW$$Limit; // 获取RW段在RAM中的结束地址
extern unsigned char Image$$RW_IRAM1$$ZI$$Limit; // 获取ZI段在RAM中的结束地址
所以在MDK中只需要使用Image$$RW_IRAM1$$ZI$$Limit链接便可获得栈空间的结束地址,如下所示:
extern int Image$$RW_IRAM1$$ZI$$Limit;
#define HEAP_BEGIN ((void *)&Image$$RW_IRAM1$$ZI$$Limit)IAR环境下,栈结束地址的获取,如下所示:
#pragma section="CSTACK"
#define HEAP_BEGIN (__segment_end("CSTACK"))
GCC环境下,栈结束地址的获取,如下所示:
extern int __bss_end;
#define HEAP_BEGIN ((void *)&__bss_end)
四、RT-Thread程序更改
只需要在 board.h 文件中定义相关宏即可,然后修改 board.c 文件中rt_system_heap_init函数 的内存获取地址。
board.h 文件
/*
* Change Logs:
* Date Author
* 2022-06-29 jiaozhu
*/
#ifndef __BOARD_H__
#define __BOARD_H__
#include "stm32f10x.h"
#include "drv_gpio.h"
#include "drv_usart.h"
#ifdef __cplusplus
extern "C"
{
#endif
/*-------------------------- ROM/RAM CONFIG BEGIN --------------------------*/
#define ROM_START ((uint32_t)0x08000000)
#define ROM_SIZE (64 * 1024)
#define ROM_END ((uint32_t)(ROM_START + ROM_SIZE))
#define RAM_START (0x20000000)
#define RAM_SIZE (20 * 1024)
#define RAM_END (RAM_START + RAM_SIZE)
#define STM32_SRAM1_END RAM_END
/*-------------------------- GET HEAP SIZE --------------------------*/
#if defined(__CC_ARM) || defined(__CLANG_ARM)
extern int Image$$RW_IRAM1$$ZI$$Limit;
#define HEAP_BEGIN ((void *)&Image$$RW_IRAM1$$ZI$$Limit)
#elif __ICCARM__
#pragma section="CSTACK"
#define HEAP_BEGIN (__segment_end("CSTACK"))
#else
extern int __bss_end;
#define HEAP_BEGIN ((void *)&__bss_end)
#endif
#define HEAP_END STM32_SRAM1_END
#ifdef __cplusplus
}
#endif
#endif /* __BOARD_H__ */
board.C 文件
/*
* Copyright (c) 2006-2019, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2017-07-24 Tanek the first version
* 2018-11-12 Ernest Chen modify copyright
*/
#include <rtthread.h>
#include <board.h>
#define _SCB_BASE (0xE000E010UL)
#define _SYSTICK_CTRL (*(rt_uint32_t *)(_SCB_BASE + 0x0))
#define _SYSTICK_LOAD (*(rt_uint32_t *)(_SCB_BASE + 0x4))
#define _SYSTICK_VAL (*(rt_uint32_t *)(_SCB_BASE + 0x8))
#define _SYSTICK_CALIB (*(rt_uint32_t *)(_SCB_BASE + 0xC))
#define _SYSTICK_PRI (*(rt_uint8_t *)(0xE000ED23UL))
// Updates the variable SystemCoreClock and must be called
// whenever the core clock is changed during program execution.
extern void SystemCoreClockUpdate(void);
// Holds the system core clock, which is the system clock
// frequency supplied to the SysTick timer and the processor
// core clock.
extern uint32_t SystemCoreClock;
void STM32F10x_peripheral_init(void)
{
// Initialize serial port
USART1_Config();
// Initialize LED
LED_GPIO_Config();
}
static uint32_t _SysTick_Config(rt_uint32_t ticks)
{
if ((ticks - 1) > 0xFFFFFF)
{
return 1;
}
_SYSTICK_LOAD = ticks - 1;
_SYSTICK_PRI = 0xFF;
_SYSTICK_VAL = 0;
_SYSTICK_CTRL = 0x07;
return 0;
}
/**
* This function will initial your board.
*/
void rt_hw_board_init()
{
STM32F10x_peripheral_init();
/* System Clock Update */
SystemCoreClockUpdate();
/* System Tick Configuration */
_SysTick_Config(SystemCoreClock / RT_TICK_PER_SECOND);
#if defined(RT_USING_USER_MAIN) && defined(RT_USING_HEAP)
rt_system_heap_init((void *) HEAP_BEGIN, (void *) HEAP_END);
#endif
/* Set the shell console output device */
#if defined(RT_USING_DEVICE) && defined(RT_USING_CONSOLE)
rt_console_set_device(RT_CONSOLE_DEVICE_NAME);
#endif
/* Board underlying hardware initialization */
#ifdef RT_USING_COMPONENTS_INIT
rt_components_board_init();
#endif
}
void SysTick_Handler(void)
{
/* enter interrupt */
rt_interrupt_enter();
rt_tick_increase();
/* leave interrupt */
rt_interrupt_leave();
}
五、堆区和栈区的空间使用查看
栈空间的使用情况查看
因为栈空间的管理直接是由编译管理的,所以编译完成后直接可以看到编译器查看(这里以MDK环境为例),如下图所示:

从图中可知,栈空间的使用等于208+3448(字节)。
堆空间的使用情况查看
在RT-Thread 有相应内存管理算法,也提供了堆内存是查看方式,所以只需要在 FinSH 中使用 free 指令查看即可,如下图所示,对于 FinSH 不了解的小伙伴,可以查看STM32 移植 RT-Thread 标准版的 FinSH 组件

参考文献
STM32链接脚本详解:https://blog.csdn.net/qq_27575841/article/details/104373417
RT-Thread 堆区大小设置的更多相关文章
- 按字节读取txt文件缓存区大小设置多少比较好?
读取 txt 文件常规写法有逐行读取和按照字节缓存读取,那么按照字节缓存读取时,设置缓存区多大比较好呢?百度了一下,没发现有说这个问题的,自测了一把,以事实说话. 常规读取方法如下: // 字节流读取 ...
- Heap堆的理解以及在IAR中如何设置堆的大小
文章首发于浩瀚先森博客 堆栈的概念在脑海里已经存在有一段时间了,今天就测试来整理下Heap堆.栈以后再说. 堆区不像全局变量和局部变量总是有指定的内存大小,它是为了在程序运行时动态分配内存而设定的一块 ...
- jvm详情——6、堆大小设置简单说明
年轻代的设置很关键JVM中最大堆大小有三方面限制:相关操作系统的数据模型(32-bt还是64-bit)限制:系统的可用虚拟内存限制:系统的可用物理内存限制.32位系统下,一般限制在1.5G~2G:64 ...
- Hadoop作业JVM堆大小设置优化 [转]
前段时间,公司Hadoop集群整体的负载很高,查了一下原因,发现原来是客户端那边在每一个作业上擅自配置了很大的堆空间,从而导致集群负载很高.下面我就来讲讲怎么来现在客户端那边的JVM堆大小的设置.我们 ...
- 一步步优化JVM四:决定Java堆的大小以及内存占用
到目前为止,还没有做明确的优化工作.只是做了初始化选择工作,比如说:JVM部署模型.JVM运行环境.收集哪些垃圾回收器的信息以及需要遵守垃圾回收原则.这一步将介绍如何评估应用需要的内存大小以及Java ...
- 了解java虚拟机—堆相关参数设置(3)
堆相关配置 -Xmx 最大堆空间 -Xms 初始堆空间大小,如果初始堆空间耗尽,JVM会对堆空间扩容,其扩展上限为最大堆空间.通常-Xms与-Xmx设置为同样大小,避免扩容造成性能损耗. -Xmn 设 ...
- JVM笔记五-堆区
JVM笔记五-堆区 在JVM中,堆区是重中之重.通过前面文章的学习,我们知道了,栈区是不会有垃圾回收的,所以,经常说的垃圾回收,其实就是回收的是堆区的数据.在这里,我们将会看到传说中的,新生代.老年代 ...
- IOS 杂笔-17(堆区栈区等)
栈区(stack):由系统自动分配,一般存放函数参数值.局部变量的值等.由编译器自动创建与释放.其操作方式类似于数据结构中的栈,即后进先出.先进后出的原则. 例如:在函数中申明一个局部变量int b; ...
- iOS程序中的内存分配 栈区堆区全局区
在计算机系统中,运行的应用程序的数据都是保存在内存中的,不同类型的数据,保存的内存区域不同.一.内存分区 栈区(stack) 由编译器自动分配并释放,存放函数的参数值,局部变量等.栈是系统数据结构,对 ...
- 闪回恢复区大小不够。报ORA-19809、ORA-19804
问题: 闪回恢复区大小不够,rman默认备份路径报错.RMAN> backup database;Starting backup at 01-DEC-14using target databas ...
随机推荐
- 记录--这样封装列表 hooks,一天可以开发 20 个页面
这里给大家分享我在网上总结出来的一些知识,希望对大家有所帮助 这样封装列表 hooks,一天可以开发 20 个页面 前言 在做移动端的需求时,我们经常会开发一些列表页,这些列表页大多数有着相似的功能: ...
- B站框框老师+宋浩老师概率论视频课笔记,宋浩老师数理统计视频课笔记
只做理解类记录,哪个知识点忘了去看视频.前四章是概率,看的框框老师. 概率论 1.随机试验:可重复性.可预知性.不确定性 2.样本空间:随机试验E的所有可能结果,记为S或Ω 3.样本点:样本空间中的每 ...
- ftp安装与配置 云服务器 CentOS7
1.FTP的安装 #安装 yum install -y vsftpd #设置开机启动 systemctl enable vsftpd.service #启动 systemctl start vsftp ...
- Gaussian YOLOv3 : 对bbox预测值进行高斯建模输出不确定性,效果拔群 | ICCV 2019
在自动驾驶中,检测模型的速度和准确率都很重要,出于这个原因,论文提出Gaussian YOLOv3.该算法在保持实时性的情况下,通过高斯建模.损失函数重建来学习bbox预测值的不确定性,从而提高准确率 ...
- KingbaseES V8R6集群部署案例之---脚本部署节点环境检查故障
KingbaseES V8R6集群部署案例之---脚本部署节点环境检查故障 案例说明: KingbaseES V8R6集群在部署前会对集群节点系统环境进行检测,检测失败后,将中断部署:其中一个检测项, ...
- 【问题解决1】fatal error: X11/XXXX.h: No such file or directory
问题现象 编译鸿蒙代码时,报如下类似的错误: 错误1: 错误2: 解决方法 step 1:安装依赖文件 sudo apt-get install apt-file sudo apt-file upda ...
- #根号分治,分块,dfs序#洛谷 7710 [Ynoi2077] stdmxeypz
题目传送门 分析 首先把距离变成深度,用dfs序转成区间问题,考虑分块,散块直接改 问题是整块,如果模数比较大,可以以深度为第一维下标差分标记,这样查询时就可以前缀和知道答案 如果模数比较小,那么给该 ...
- #错排,组合计数#洛谷 4071 [SDOI2016]排列计数
题目 多组询问长度为\(n\)的排列中恰好有\(m\)个数对号入座的排列数 分析 首先\(n\)个数中选择\(m\)个数放入那\(m\)个位置显然是\(C(n,m)\) 剩下就是错排\(D(n)=(n ...
- VS的 x86_64 , x64_86 , x64 , x86 有什么区别
x86 Native Tools Command Prompt - Sets the environment to use 32-bit, x86-native tools to build 32-b ...
- Matplotlib绘图设置--- 图例设置
plt.legend()和ax.legend()参数设置 自动会将每条线的标签与其风格.颜色进行匹配. plt.legend(*args, **kwargs) Place a legend on th ...