当前位置: 首页 > news >正文

嵌入式系统内存分段核心内容详解

一、嵌入式内存分段整体规则(按地址从低到高)

        嵌入式系统内存按 “功能 + 属性” 划分为 6 个核心段,地址从低到高依次分布,各段职责与存储对象明确,具体规则如下表:

地址范围段类型(Segment)对应段标识 / 关键字核心存储内容
低地址代码段(Code Segment).text编译后的机器指令、程序执行逻辑、#define定义的常量
常量段(Const Segment).rodata字符串常量(如"hello")、数字常量(如const int a=10)、const修饰的全局变量
全局 / 静态段(Global/Static Segment).bss.data.bss:未初始化的全局 / 静态变量、初始化为 0 的全局 / 静态变量
.data:已初始化(非 0)的全局 / 静态变量
堆段(Heap Segment)无固定标识开发者通过malloc手动分配的动态内存、需手动free释放的内存
高地址栈段(Stack Segment)无固定标识局部变量(如函数内int x=5)、const修饰的局部变量、函数形参、函数返回值

关键地址增长特性

  • 堆段:从低地址向高地址增长,由隐式指针跟踪分配边界;
  • 栈段:从高地址向低地址增长,遵循 “先进后出(FILO)” 规则,与数据结构中的 “栈” 逻辑一致。

二、各段核心属性与物理存储

不同段的读写权限、初始化方式、物理位置差异显著,直接影响嵌入式系统的资源占用与运行效率,具体细节如下:

1. 代码段(.text)

  • 核心属性
    • 权限:只读 + 可执行(不可修改,防止程序指令被意外篡改);
    • 初始化:由编译器将 C/C++ 代码编译为机器指令后生成,无需手动干预;
    • 物理存储:固定存于Flash( ,因代码无需运行中修改,且 Flash 非易失性可长期保存程序。
  • 典型场景:函数体逻辑(如void init(void)的指令)、程序主流程(main函数指令)。

2. 常量段(.rodata)

  • 核心属性
    • 权限:只读(运行中不可修改,若强行修改会触发硬件 / 软件保护);
    • 初始化:编译时由编译器将常量数据(如字符串、const全局变量)打包生成;
    • 物理存储:仅存于Flash,嵌入式系统中所有 “只读(RO)” 数据均不占用 SRAM(静态存储器),避免宝贵的 SRAM 资源浪费。
  • 易混淆点:函数内的字符串常量(如char* s="test")也存于.rodata,而非栈段;const局部变量则存于栈段(仅编译期限制修改,物理位置在 SRAM)。

3. 全局 / 静态段(.bss + .data)

(1).bss 段
  • 核心属性
    • 权限:可读可写(运行中可修改变量值,如int g_val; g_val=10;);
    • 初始化:不占用 BIN/ELF 文件空间,程序启动时由启动代码自动清零(无需开发者手动初始化);
    • 物理存储:仅存于SRAM,因全局 / 静态变量需运行中快速访问,SRAM 无需刷新、读写速度远快于 Flash。
  • 包含对象:未初始化的全局变量(如int g_uninit;)、初始化为 0 的静态变量(如static int s_zero=0;)。
(2).data 段
  • 核心属性
    • 权限:可读可写(运行中可修改,如int g_init=5; g_init=8;);
    • 初始化:占用 BIN/ELF 文件空间,编译时将初始值写入文件,程序启动后从 Flash 加载到 SRAM;
    • 物理存储:运行时存于SRAM(保证访问速度),初始数据备份于 Flash(非易失性保存)。
  • 关键影响:若全局 / 静态变量初始值非 0(如uint8_t buf[256*1024]={1};),会直接导致 BIN 文件增大 —— 因.data段需存储完整的初始化数据。

4. 堆段(Heap)

  • 核心属性
    • 权限:可读可写(动态分配的内存可自由修改,如char* p=malloc(10); p[0]='a';);
    • 初始化:开发者通过malloc/calloc手动初始化(如int* arr=malloc(4*5);),需通过free手动释放;
    • 物理存储:仅存于SRAM,因动态内存需快速读写,且运行中需灵活调整大小。
  • 风险点:未及时free会导致内存泄漏,长期运行会耗尽 SRAM;频繁分配 / 释放可能产生内存碎片,导致后续malloc失败(即使总剩余内存足够)。

5. 栈段(Stack)

  • 核心属性
    • 权限:可读可写(局部变量可修改,如void func(){int x=3; x=5;});
    • 初始化:由编译器自动管理,变量进入作用域时自动分配栈空间,离开作用域时自动释放(无需手动操作);
    • 物理存储:仅存于SRAM,栈访问依赖 CPU 寄存器(如栈指针 SP),速度极快。
  • 关键限制
    • 栈空间大小固定(由链接脚本配置,如STACK_SIZE = 0x1000),若局部变量过大(如char buf[1024*1024];)或递归调用过深,会导致栈溢出(程序崩溃);
    • 作用域限制:栈变量离开定义范围后即失效(如函数返回后,其内部局部变量地址变为 “无效地址”)。

三、段相关开发实践要点

结合嵌入式系统 “资源受限(SRAM/Flash 容量小)” 的特点,段的合理使用直接决定系统稳定性与资源利用率,核心实践要点如下:

1. 避免 BIN 文件膨胀:优先用.bss 段存大缓冲区

若需定义大缓冲区(如 256K/512K),避免使用.data段(如uint8_t buf[512*1024]={0};)—— 会导致 BIN 文件增大 512K;应定义为未初始化变量(uint8_t buf[512*1024];),使其进入.bss段,不占用 BIN 空间,仅运行时占用 SRAM。

2. 减少 SRAM 占用:只读数据放入.rodata

  • 全局常量(如配置参数const int MAX_LEN=1024)、固定字符串(如日志格式const char* LOG_FMT="[%s] %s")需加const修饰,确保进入.rodata段(存于 Flash),不消耗 SRAM;
  • 避免将 “无需修改的数据” 定义为全局变量(如int g_fixed=10),应改为const int g_fixed=10,节省 SRAM。

3. 栈段使用禁忌:不定义过大局部变量

  • 函数内避免定义大数组(如void func(){char big_buf[64*1024];}),若需大缓冲区,优先用malloc(堆)或全局.bss变量;
  • 递归函数需控制深度(如递归层级不超过 100),防止栈溢出,可改用迭代实现。

4. 堆段使用原则:减少动态分配,优先静态内存池

  • 嵌入式系统中,堆的malloc/free易导致内存碎片,关键场景(如实时控制)建议用 “静态内存池” 替代(预先分配一块连续 SRAM,手动管理分配 / 释放);
  • 若使用堆,需确保malloc返回值非NULL(判断内存分配是否成功),且配对使用free(避免泄漏)。

5. 链接脚本配置:明确段的内存分配

通过链接脚本(.ld 文件)指定各段的物理地址与大小,避免段重叠(如堆与栈重叠导致内存 corruption),示例配置:

/* 定义Flash和SRAM地址范围 */
MEMORY {FLASH (rx)  : ORIGIN = 0x08000000, LENGTH = 1024K  /* 代码段、常量段存于此 */SRAM (rwx)  : ORIGIN = 0x20000000, LENGTH = 128K   /* .bss、.data、堆、栈存于此 */
}/* 分配各段到指定内存 */
SECTIONS {.text : { *(.text) *(.rodata) } > FLASH  /* 代码段+常量段放入Flash */.data : { *(.data) } > SRAM AT > FLASH   /* .data初始值存Flash,运行时加载到SRAM */.bss  : { *(.bss) } > SRAM               /* .bss直接放入SRAM */heap_start = .;                          /* 堆起始地址(.bss结束后) */stack_start = ORIGIN(SRAM) + LENGTH(SRAM);/* 栈起始地址(SRAM最高地址) */
}

文章转载自:

http://w3VnhCrG.xkhxL.cn
http://1HRp8jhx.xkhxL.cn
http://UKmZE5Vy.xkhxL.cn
http://alRmy2BM.xkhxL.cn
http://i8N996d6.xkhxL.cn
http://8yggUILc.xkhxL.cn
http://kvGQdMDd.xkhxL.cn
http://AMZVObOa.xkhxL.cn
http://zHzdwQ4w.xkhxL.cn
http://ckeIhSKI.xkhxL.cn
http://tAfOvequ.xkhxL.cn
http://oSHTccSg.xkhxL.cn
http://bNRRV1v7.xkhxL.cn
http://hgDDVQsQ.xkhxL.cn
http://NTu060mx.xkhxL.cn
http://lnjRIX5L.xkhxL.cn
http://xtqYNOWq.xkhxL.cn
http://KSc5Ap8z.xkhxL.cn
http://vG43rZvX.xkhxL.cn
http://XRMQNdTH.xkhxL.cn
http://CpauGtlu.xkhxL.cn
http://O2i8D7mR.xkhxL.cn
http://cszMTkXo.xkhxL.cn
http://2XZ91blF.xkhxL.cn
http://kxokRvUo.xkhxL.cn
http://8e7Arf9B.xkhxL.cn
http://FTiBhOXH.xkhxL.cn
http://qWUFwWsE.xkhxL.cn
http://zWf46aCt.xkhxL.cn
http://1mePt8Jt.xkhxL.cn
http://www.dtcms.com/a/381326.html

相关文章:

  • AI生成内容检测的综合方法论与技术路径
  • 材料基因组计划(MGI)入门:高通量计算与数据管理最佳实践
  • 系统地总结一下Python中关于“遍历”的知识点
  • Android面试指南(九)
  • Halcon编程指南:符号与元组操作详解
  • 嵌入式第五十二天(GIC,协处理器,异常向量表)
  • 嵌入式学习day48-硬件-imx6ul-key、中断
  • 查找算法和递推算法
  • Webman 微服务集成 RustFS 分布式对象存储
  • 基于51单片机的太阳能锂电池充电路灯
  • 【人工智能通识专栏】第十三讲:图像处理
  • 滚动分页查询-通俗解释
  • 电缆工程量计算-批量测量更轻松
  • UDS NRC速查
  • L2-【英音】地道语音语调--语调
  • 13.渗透-.Linux基础命令(五)-用户管理(修改用户密码)
  • 解决串口数据乱序问题
  • 智能化集成系统(IBMS):构建智慧建筑 “中枢大脑” 的全方案
  • 基于游标(Cursor)的方式来实现滚动分页
  • 30.线程的互斥与同步(四)
  • 《没有架构图?用 netstat、ss、tcpdump 还原服务连接与数据流向》
  • 仓颉语言编程入门:第一个 Windows 下的仓颉应用程序
  • 台达A2E
  • 【操作系统核心考点】进程调度算法全面总结:高频题型与易错点解析
  • ethercat在线调试工具
  • python base core partment-day07-异常、模块、包(对零基础小白友好)
  • 如何解决pip安装报错ModuleNotFoundError: No module named ‘vaex’问题
  • Acrobat JavaScript 代码中的颜色
  • TCGA单癌肿按单基因高低分组的转录组差异热图分析作图教程
  • SSRF:CVE-2021-40438