news 2026/4/19 11:25:41

程序运行在RAM或者在FLASH的区别

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
程序运行在RAM或者在FLASH的区别

程序代码存储在FLASH中,但CPU执行代码时,指令和数据需要被读取到RAM中。然而,在某些嵌入式系统(尤其是资源受限的MCU)中,为了节省宝贵的RAM空间,开发者可以选择让代码直接在FLASH中执行(Execute In Place, XIP),也可以选择将代码或数据复制到RAM中执行。这两种方式在性能、功耗、可靠性和内存占用上存在显著差异。

下表从核心维度对比了程序运行在RAM与FLASH中的主要区别:

对比维度程序在 FLASH 中执行 (XIP)程序在 RAM 中执行
执行速度较慢。FLASH(尤其是NOR Flash)的读取速度远低于RAM。访问延迟高,通常需要插入等待状态,导致CPU流水线停顿。极快。SRAM的访问速度与CPU主频匹配,可实现零等待访问,充分发挥CPU性能。
功耗相对较低。仅在CPU取指时对FLASH进行读取操作,静态功耗小。相对较高。RAM(特别是SRAM)为保持数据需要持续供电,其静态功耗和动态功耗通常高于FLASH。
启动时间。系统上电后,CPU可直接从FLASH固定地址(如0x08000000)取指执行,无需额外搬运。慢(有搬运过程)。需要一段启动代码(Bootloader)将应用程序代码从FLASH复制到RAM,然后跳转到RAM执行,增加了启动延迟。
内存占用不占用RAM空间。代码本身存储在FLASH,仅运行时栈、堆和全局变量占用RAM。占用大量RAM空间。代码段(.text)和常量数据(.rodata)需要被完整复制到RAM,极大地挤占了本可用于数据和栈的RAM资源。
代码修改困难/不可行。大多数用于存储代码的FLASH(NOR)不支持像RAM一样的字节级快速写入。若要更新代码,通常需要整扇区擦除再写入,过程复杂且耗时,无法作为动态修改代码的场所。灵活。RAM支持字节级快速读写,可用于动态加载、解释执行(如字节码)或自我修改代码等高级场景。
可靠性。FLASH是非易失性存储器,断电后代码不丢失。代码存储区域通常受到写保护,不易被意外修改。。RAM是易失性存储器,断电后内容丢失。同时,RAM区域更容易受到程序跑飞或缓冲区溢出等错误的影响,导致代码被破坏。
典型应用场景1.绝大多数MCU应用:资源有限,代码直接在FLASH中执行是标准模式。
2.启动代码(Bootloader):本身在FLASH中执行,负责初始化并加载主程序。
3.固件存储:存储不可变的核心程序。
1.性能关键代码:如中断服务程序(ISR)、数字信号处理(DSP)循环、高速通信协议处理函数。
2.需要动态加载的模块:如插件、脚本引擎。
3.从低功耗模式快速唤醒:将唤醒后要执行的代码放在RAM中,避免访问慢速FLASH。

深入分析:速度差异的原理与影响

速度差异是两者最核心的区别,其根本原因在于存储器技术本身。

FLASH(以NOR Flash为例)的读取操作涉及复杂的电压控制和解码过程,其随机读取延迟通常在几十到上百纳秒量级。而现代MCU的CPU周期可能只有几纳秒。因此,当CPU直接从FLASH取指时,常常需要插入等待周期(Wait States)。例如,STM32系列MCU的FLASH访问控制寄存器(FLASH_ACR)就需要根据CPU频率(HCLK)来配置正确的等待周期(LATENCY),否则CPU会读到错误的数据。

RAM(以SRAM为例)的访问则是通过静态触发器阵列实现,其访问时间与CPU时钟周期同量级,可以实现同步访问,无需等待状态。

这种速度差异对性能的影响是巨大的。以下面的一个简单延时循环为例,分析其在不同存储器中执行的时钟周期差异:

// 一个简单的空循环,常用于短延时 void delay_loop(uint32_t count) { while(count--) { __asm__ volatile ("nop"); // 执行一个空操作指令 } }

假设CPU主频为72MHz,一个时钟周期约为13.9ns。

  • 在FLASH中执行(假设需2个等待状态):每次从FLASH读取nop指令都可能需要3个时钟周期(1个取指 + 2个等待)。那么执行一次nop循环迭代的实际耗时可能超过3个周期。
  • 在RAM中执行(零等待)nop指令可以每个时钟周期执行一次。

因此,将delay_loop这类被频繁调用的短函数或中断服务程序搬到RAM中执行,可以显著提升系统的实时响应能力和整体吞吐量。许多MCU的驱动库(如STM32 HAL)会提供编译指令或链接器修饰符,将特定的函数段(.ramfunc)分配到RAM中执行。

实践配置:如何将代码放入RAM执行

将代码放入RAM执行通常需要两个步骤:链接脚本配置代码修饰

1. 链接脚本(.ld文件)修改
需要明确定义一个RAM区域用于存放代码,并将特定的输入段映射到该区域。

/* 定义内存区域 */ MEMORY { FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 256K RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 64K } /* 定义段 */ SECTIONS { /* .text 主代码段仍然放在FLASH */ .text : { *(.text) /* 所有 .text 输入段 */ *(.text*) /* 所有其他 .text 输入段 */ } >FLASH /* 新增一个名为 .ram_code 的段,将其放入RAM */ .ram_code : { . = ALIGN(4); _sram_code = .; /* 创建符号,记录段起始地址 */ *(.ram_code) /* 收集所有被标记为 .ram_code 的输入段 */ *(.ram_code*) . = ALIGN(4); _eram_code = .; /* 创建符号,记录段结束地址 */ } >RAM AT> FLASH /* VMA在RAM,但LMA(加载地址)在FLASH */ /* ... 其他段(.data, .bss等)... */ }

关键点:>RAM AT> FLASH表示这个段的运行时地址(VMA)在RAM中,但它的加载地址(LMA)在FLASH中。这意味着代码被烧录在FLASH里,但上电后需要被复制到RAM的指定位置才能正确执行。

2. 代码修饰与启动搬运
在C代码中,使用特定属性将函数或变量分配到自定义的段中。

/* 使用GCC编译器属性,将函数 fast_isr 放到 .ram_code 段 */ void __attribute__((section(".ram_code"))) fast_isr(void) { // 高性能中断处理代码 // ... } /* 对于IAR编译器,通常使用 `#pragma location` */ // #pragma location = ".ram_code" // void fast_isr(void);

然后,在系统的启动文件(如startup_*.s)或main()函数之前的初始化代码中,需要添加将.ram_code段从FLASH复制到RAM的代码。

/* 复制 .ram_code 段从FLASH到RAM */ extern uint32_t _sram_code, _eram_code, _sram_code_load; void copy_ram_code(void) { uint32_t *src = &_sram_code_load; // 在FLASH中的加载地址 uint32_t *dst = &_sram_code; // 在RAM中的运行地址 while (dst < &_eram_code) { *dst++ = *src++; } } // 在系统初始化时调用 copy_ram_code()

总结与选型建议

选择在RAM还是FLASH中运行程序,是嵌入式系统设计中的一种重要权衡。

  • 默认且最常用的模式是XIP(在FLASH中执行)。它节省RAM,启动快,可靠性高,足以满足大多数控制类、逻辑处理类应用的需求。
  • 仅在必要时将关键代码搬运至RAM执行。这是一种优化手段,用于解决FLASH访问速度带来的性能瓶颈。其代价是牺牲了宝贵的RAM空间,并增加了启动复杂度和功耗。

决策流程建议

  1. 优先XIP:所有代码默认在FLASH中运行。
  2. 性能剖析:使用性能分析工具或计时器,找出系统中的热点函数或最苛刻的中断服务程序。
  3. 局部优化:仅将这些经证实的性能瓶颈函数迁移到RAM中执行。
  4. 平衡验证:评估优化后,RAM的剩余容量是否仍能满足堆栈和全局数据的需求,确保系统稳定。

简而言之,FLASH是程序的“家”,用于可靠存储;RAM是程序的“工作间”,用于高速执行。合理规划两者的用途,是优化嵌入式系统性能与资源的关键。


参考来源

  • 【物联网】ROM、RAM和FLASH的区别
  • FLASH和EEPROM的区别
  • ROM, FLASH和RAM的区别
  • ROM、RAM、SRAM、DRAM、FLASH区别(转载+梳理)
  • ROM 、RAM和FLASH 的区别
  • ROM、RAM、DRAM、SRAM、SDRAM和FLASH的区别
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/19 11:24:53

2024热门AI工具:轻松实现AI写专著,20万字专著高效生成!

对于许多学术研究者来说&#xff0c;撰写学术专著时最大的挑战无疑来自“时间有限”和“需求无限”的矛盾。通常&#xff0c;撰写一本专著可能需要耗时三到五年&#xff0c;甚至更久&#xff0c;而研究者们除了写作外&#xff0c;还需要处理教学、进行科研项目、参与学术交流等…

作者头像 李华
网站建设 2026/4/19 11:22:20

面试官问我‘0.(9)是否等于1’:从数学原理到代码实现的高频考点解析

面试官问我‘0.(9)是否等于1’&#xff1a;从数学原理到代码实现的高频考点解析 当你在技术面试中被问到"0.999...无限循环是否等于1"时&#xff0c;这绝不是一个简单的脑筋急转弯。这个问题背后隐藏着计算机科学中关于数字表示的深刻原理&#xff0c;也是检验工程师…

作者头像 李华
网站建设 2026/4/19 11:19:15

Zynq 7000 DAP子系统详解:如何利用Arm CoreSight进行高效调试

Zynq 7000 DAP子系统深度解析&#xff1a;Arm CoreSight调试实战指南 在嵌入式系统开发中&#xff0c;高效的调试能力往往决定着项目的成败。Xilinx Zynq 7000系列SoC凭借其独特的Arm CoreSight调试架构&#xff0c;为开发者提供了强大的硬件辅助调试手段。本文将带您深入探索D…

作者头像 李华
网站建设 2026/4/19 11:16:15

Windows上安装Android应用的3个关键突破:APK-Installer全解析

Windows上安装Android应用的3个关键突破&#xff1a;APK-Installer全解析 【免费下载链接】APK-Installer An Android Application Installer for Windows 项目地址: https://gitcode.com/GitHub_Trending/ap/APK-Installer 你是否曾经遇到过这样的困境&#xff1a;在Wi…

作者头像 李华
网站建设 2026/4/19 11:13:24

实测GPTZero:ChatGPT、Claude和文心一言的AI检测效果大比拼(附避坑指南)

AI内容检测实战&#xff1a;GPTZero对ChatGPT、Claude与文心一言的识别效果深度评测 当AI生成内容如潮水般涌入教育、媒体和商业领域&#xff0c;如何辨别真伪成为摆在专业人士面前的现实挑战。GPTZero作为当前最受关注的AI文本检测工具之一&#xff0c;其实际表现究竟如何&…

作者头像 李华