单片机内存区域划分

目录

  • 一、C 语言内存分区
    • 1、栈区
    • 2、堆区
    • 3、全局区(静态区)
    • 4、常量区
    • 5、代码区
    • 6、总结
  • 二、单片机存储分配
    • 1、存储器
      • 1.1 RAM
      • 1.2 ROM
      • 1.3 Flash Memory
      • 1.4 不同数据的存放位置
    • 2、程序占用内存大小


一、C 语言内存分区

C 语言在内存中一共分为如下几个区域,分别是:

下面分别介绍各个区域。

1、栈区

栈区介绍:

  • 栈区由编译器自动分配释放,由操作系统自动管理,无须手动管理。
  • 栈区由编译器自动分配释放,由操作系统自动管理,无须手动管理。
  • 栈区上的内容只在函数范围内存在,当函数运行结束,这些内容也会自动被销毁。
  • 栈区按内存地址由高到低方向生长,其最大大小由编译时确定,速度快,但自由性差,最大空间不大。
  • 栈区是先进后出原则(LIFO),其操作方式数据结构中的栈是一样的。

存放内容:

  • 临时创建的局部变量存放在栈区。
  • 函数调用时,其入口参数存放在栈区。
  • 函数返回时,其返回值存放在栈区。
  • const 定义的局部变量存放在栈区。

栈的大小是有限的,通常 Visual C++ 编译器的默认栈的大小为 1MB,所以不要定义 int a[1000000] 这样的超大数组。

2、堆区

  • 堆区按内存地址由低到高方向生长,其大小由系统内存/虚拟内存上限决定,速度较慢,但自由性大,可用空间大。
  • 堆区用于存放程序运行中被动态分布的内存段,可增可减。
  • 可以有 malloc 等函数实现动态分布内存,不过它的存储空间一般是不连续的,所以会产生内存碎片。
  • 有 malloc 函数分布的内存,必须用 free 进行内存释放,否则会造成内存泄漏。
  • 注意它与数据结构中的堆是两回事,不过分配方式类似于链表。
char* p = new char[20];
// 这行代码在Heap中开辟了20个char长度的空间,同时在Stack上压入了p,
// 指针变量p存在于栈上,其值为刚刚在堆上开辟的空间的首地址。

3、全局区(静态区)

全局区由 .bss 段和 .data 段组成,可读可写。

通常是用于那些在编译期间就能确定存储大小的变量的存储区,但它用于的是在整个程序运行期间都可见的全局变量和静态变量。

  • .bss 段 ——未初始化
    • 未初始化的全局变量和未初始化的静态变量存放在 .bss段
    • 初始化为 0 的全局变量和初始化为0的静态变量存放在 .bss段
    • .bss段 不占用可执行文件空间,其内容由操作系统初始化。
  • .data段 ——已初始化
    • 已初始化的全局变量存放在 .data段
    • 已初始化的静态变量存放在 .data段
    • .data段 占用可执行文件空间,其内容由程序初始化。

注意,.bss段 只占运行时的内存空间而不占文件空间。在程序运行的整个周期内,.bss段 的数据一直存在

4、常量区

同样,常量区也是用于那些在编译期间就能确定存储大小的常量的存储区,并且在程序运行期间,存储区内的常量是全局可见的。这是一块比较特殊的存储去,他们里面存放的是常量,不允许被修改。

  • 字符串数字等常量存放在常量区。
  • const 修饰的全局变量存放在常量区。
  • 程序运行期间,常量区的内容不可以被修改。

常量数据段叫做 .rodata,即 read only,表示常量数据是不可修改的。一旦程序中对其修改将会出现段错误:

  • 程序中的常量不一定就放在 .rodata 中,有的立即数和指令编码放在 .text
  • 对于字符串常量,若程序中存在重复的字符串,编译器会保证只存在一个
  • .rodata 是在多个进程间共享的
  • 有的嵌入式系统,.rodata 放在 ROM(或者 NOR FLASH)中,运行时直接读取无需加载至 RAM。想要将数据放在 .rodata 只需要加上 const 属性修饰即可。

5、代码区

  • 程序执行代码存放在代码区,其值不能修改(若修改则会出现错误)。
  • 字符串常量和 define 定义的常量也有可能存放在代码区。

6、总结

下面已一段代码来看一下各部分存储:

#include <stdio.h>static unsigned int val1 = 1;         // val1存放在.data段
unsigned int val2 = 1;                // 初始化的全局变量存放在.data段
unsigned int val3 ;                   // 未初始化的全局变量存放在.bss段
const unsigned int val4 = 1;          // val4存放在.rodata(只读数据段)unsigned char Demo(unsigned int num)  // num 存放在栈区
{  char var = "123456";              // var存放在栈区,"123456"存放在常量区  unsigned int num1 = 1 ;           // num1存放在栈区  static unsigned int num2 = 0;     // num2存放在.data段  const unsigned int num3 = 7;      // num3存放在栈区  void *p;  p = malloc(8);                    // p存放在堆区  free(p); return 1;
}void main()
{  unsigned int num = 0 ;  num = Demo(num);                  // Demo()函数的返回值存放在栈区。
}

注意:静态局部变量和静态全局变量


属于静态存储方式的量不一定就是静态变量。


例如:全局变量虽属于静态存储方式,但不一定是静态变量,必须由 static 加以定义后才能成为静态外部变量,或称静态全局变量。

  • 把局部变量改变为静态变量后是改变了它的存储方式,即改变了它的生存期。
  • 把全局变量改变为静态变量后是改变了它的作用域,限制了它的使用范围。

假设现在有一个程序,它的函数调用顺序如下:

main(...) -> func_1(...) -> func_2(...) -> func_3(...),即:主函数 main 调用函数 func_1; 函数 func_1 调用函数 func_2; 函数 func_2 调用函数 func_3。

当一个程序被操作系统调入内存运行, 其对应的进程在内存中的映射如下图所示:

二、单片机存储分配

首先来看一下 RAM 和 ROM、Flash Memory 的物理特性。

1、存储器

1.1 RAM

RAM 是与 CPU 直接交换数据的内部存储器,也叫主存(内存)。它可以随时读写,而且速度很快,通常作为操作系统或其他正在运行中的程序的临时数据存储媒介。

RAM 又称随机存取存储器,存储的内容可通过指令随机读写访问。RAM 中的存储的数据在掉电是会丢失,因而只能在开机运行时存储数据。其中 RAM 又可以分为两种:

  • 一种是 Dynamic RAM(DRAM,动态随机存储器)
  • 另一种是 Static RAM(SRAM,静态随机存储器)。

1.2 ROM

ROM 又称只读存储器,只能从里面读出数据而不能任意写入数据。ROM 与 RAM 相比,具有读写速度慢的缺点。但由于其具有掉电后数据可保持不变的优点,因此常用也存放一次性写入的程序和数据,比如主版的 BIOS 程序的芯片就是 ROM 存储器。

1.3 Flash Memory

由于 ROM 具有不易更改的特性,后面就发展了 Flash Memory。Flash Memory 不仅具有 ROM 掉电不丢失数据的特点,又可以在需要的时候对数据进行更改,不过价格比 ROM 要高。

1.4 不同数据的存放位置

由前面的分析我们知道,代码区和常量区的内容是不允许被修改的,ROM(STM32 就是 Flash Memory)也是不允许被修改的,所以代码区常量区的内容编译后存储在 ROM 中。

全局区.bss段.data段)都是存放在 RAM 中。

以 STM32F407 芯片为例:
在这里插入图片描述

  • ROM 区域是 0x8000000 开始,大小是 0x10000,这片区域是只读区域,不可修改,存放代码区常量区
  • 第一个 RAM 区域是 0x20000000 开始,大小是 0x2000,这片区域是可读写区域,存放的是全局(静态)区堆区栈区

2、程序占用内存大小

下面是 Keil 的 Build Output 窗口:

如上图,存在 CodeRO-dataRW-dataZI-data 四个代码段大小。

  • Code:代码,也就是编译之后产生的机器指令。
  • RO_dataRead Only data,只读数据域,指程序中用到的只读数据,这些数据被存储在 ROM 区,因而程序不能修改其内容。这部分在程序运行过程中不能被更改,因此在运行时只需要来读取即可,无需占用 RAM 空间。
  • RW_dataRead Write data,可读写数据域,指初始化为“非 0 值”的可读写数据,程序刚运行时,这些数据具有非 0 的初始值,且运行的时候它们会常驻在 RAM 区,因而应用程序可以修改其内容。
  • ZI_dataZero Initialie data,即 0 初始化数据,它指初始化为“0 值”的可读写数据域。它与 RW-data 的区别是程序刚运行时这些数据初始值全都为 0,而后续运行过程与 RW-data 的性质一样,它们也常驻在 RAM 区,因而应用程序可以更改其内容。

从生成的 map 文件可以非常方便地看到相关信息:

R A M = R W − d a t a + Z I − d a t a R O M = C o d e + R O − d a t a + R W − d a t a RAM = RW-data + ZI-data \\ ROM = Code + RO-data + RW-data RAM=RWdata+ZIdataROM=Code+ROdata+RWdata

可以看到:对于 RAM 的空间,程序启动时首先需要把 Flash 中的 RW_data(RW)复制到 RAM 中,然后把 ZI_data 加载到 RAM中。

对应到具体的内存上,结合启动流程如下图所示。


因此,想要让一个程序正常运行。

  • 芯片的 Flash 大小 要大于 C o d e + R O − d a t a + R W − d a t a Code + RO-data + RW-data Code+ROdata+RWdata 的大小;
  • 芯片的 RAM 大小 要大于 R W − d a t a + Z I d a t a RW-data + ZI_data RWdata+ZIdata 的大小。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/414239.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

AR 眼镜之-系统通知定制(通知弹窗)-实现方案

目录 &#x1f4c2; 前言 AR 眼镜系统版本 系统通知定制 1. &#x1f531; 技术方案 1.1 技术方案概述 1.2 实现方案 1&#xff09;实现系统通知的监听 2&#xff09;系统通知显示&#xff1a;通知弹窗 2. &#x1f4a0; 实现系统通知的监听 2.1 继承 NotificationLi…

【原型设计工具评测】Axure、Figma、Sketch三强争霸

在当今的数字化设计领域&#xff0c;选择合适的原型设计工具对于项目的成功至关重要。Axure、Figma 和 Sketch 是目前市场上最受欢迎的三款原型设计工具&#xff0c;它们各具特色&#xff0c;满足了不同用户的需求。本文将对这三款工具进行详细的对比评测&#xff0c;帮助设计师…

联蔚盘云亮相CDIE消费品行业峰会

8月28日&#xff0c;由华昂集团主办&#xff0c;专注于消费品行业的2024CDIE行业峰会在广州盛大开幕。联蔚数科携子品牌联蔚盘云亮相本次大会。本次峰会汇聚了众多企业高管&#xff0c;行业领域专家&#xff0c;围绕AI技术前沿、数智营销新策略、会员运营以及品牌增量路径等话题…

后台框架-统一异常管理

搭建后台框架全局异常管理是一个很重要的部分&#xff0c;好在SpringBoot提供了很好的处理方法 使用ControllerAdvice ControllerAdvice是Spring MVC中的一个全局异常处理注解&#xff0c;它允许在一个地方集中处理所有控制器抛出的异常。通过使用ControllerAdvice&#xff0…

Leetcode199二叉树的右视图(java实现)

今天我们分享的题目是199题&#xff0c;题目描述如下&#xff1a; 那么本道题的解题思路呢就是使用层序遍历&#xff0c;每次将每层中的最后一个元素加入到我们的集合中。 本道题目和之前的层序遍历二叉树的题目很像&#xff0c;但是需要注意的细节。那么我会在代码中指出。 代…

Flink CDC读取Mysql时,Decimal类型数据异常,变成了字符串(源码解析及解决方案)

1. 问题说明 使用Flink CDC 读取mysql数据时,当表字段为decimal时,读取的数据变成了字符串。 如下示例: 环境: Flink 1.18.0 Flink CDC 3.1.1 mysql 8 mysql的数据如下: 使用Flink CDC读取后的数据如下: 为了方便看,复制出来就是: {“id”:1,“price”:“AZA=”,…

ClickHousez中如何定时清理过期数据库?

一、脚本清理 要在ClickHouse中自动删除过期的数据库&#xff0c;你可以使用ClickHouse的SQL命令结合外部脚本&#xff08;如Shell脚本&#xff09;和计划任务&#xff08;如cron&#xff09;来实现。下面是一个示例&#xff0c;展示如何创建一个Shell脚本来检查数据库的创建时…

[引人深思]博彩用户真的赢了吗?——多维度揭示赌博危害

1.项目背景 博彩业&#xff0c;作为全球经济中一个庞大而复杂的行业&#xff0c;吸引了无数用户参与其中&#xff0c;然而&#xff0c;在巨大的利益诱惑背后&#xff0c;博彩业对个人和社会造成的潜在危害却不容忽视&#xff0c;尽管博彩活动常被包装为“娱乐”或“休闲活动”…

VCTP论文精读

机器视觉推理自从引入神经符号机制以来取得了巨大进步&#xff0c;这使得机器能够发展出多步骤的推理链。然而&#xff0c;正如早期认知科学家所预示的那样&#xff0c;这种逻辑和符号系统基本上不适合于现实世界、常识知识的表示和推理&#xff0c;因为它们仅依赖于封闭世界的…

详解树状数组(C/C++)

树状数组&#xff08;Binary Indexed Tree&#xff0c;简称BIT或Fenwick Tree&#xff09;是一种用于高效处理数据序列的算法数据结构。它能够支持两个主要操作&#xff1a;单点更新和区间求和&#xff0c;这两个操作的时间复杂度都能达到O(log n)&#xff0c;其中 n 是数据序列…

搭建基于QT的TCP服务器与客户端

1、实现功能 1、服务器和客户端能够建立连接 2、服务器可以给客户端发送信息 3、客户端可以给服务器发送信息 2、server 2-1、widget.h #ifndef WIDGET_H #define WIDGET_H#include <QWidget> #include <QTcpServer> #include <QTcpSocket> QT_BEGIN_NA…

【LangChain】使用LangChain的提示词模板:技巧与总结

&#x1f601; 作者简介&#xff1a;前端开发爱好者&#xff0c;致力学习前端开发技术 ⭐️个人主页&#xff1a;夜宵饽饽的主页 ❔ 系列专栏&#xff1a;JavaScript小贴士 &#x1f450;学习格言&#xff1a;成功不是终点&#xff0c;失败也并非末日&#xff0c;最重要的是继续…

电感的分类

电感作为电子电路中的重要元件&#xff0c;具有多种分类方式&#xff0c;每种类型的电感都有其独特的优缺点。以下是对电感分类及其优缺点的详细分析&#xff1a; 一、按工作频率分类 高频电感&#xff1a;适用于高频电路&#xff0c;具有较高的自谐振频率和较低的损耗。 优点…

9-8 束搜索

贪心搜索 穷举搜索 束搜索 小结 序列搜索策略包括贪心搜索、穷举搜索和束搜索。 贪心搜索所选取序列的计算量最小&#xff0c;但精度相对较低。 穷举搜索所选取序列的精度最高&#xff0c;但计算量最大。 束搜索通过灵活选择束宽&#xff0c;在正确率和计算代价之间进行权衡…

Hive 案例分析(B站用户行为大数据分析)

Hive 案例分析&#xff08;B站用户行为大数据分析&#xff09; 一、案例需求二、设计数据表结构2.1 user 表结构2.2 video 表结构 三、创建数据表3.1 创建 video 数据库3.2 创建外表3.1.2 创建 external_user3.1.3 创建 external_video 3.2 创建内表3.2.1 创建 orc_user3.2.2 创…

【Qt笔记】QTreeView控件详解

目录 引言 一、QTreeView的基本用法 1. 创建QTreeView 2. 设置数据模型 3. 展开和折叠节点 4. 处理用户交互 二、自定义数据模型 1. 继承QAbstractItemModel 2. 实现必要的方法 3. 使用自定义模型 三、自定义视图和委托 1. 自定义视图 2. 自定义委托 四、过滤与…

C++ | Leetcode C++题解之第378题有序矩阵中第K小的元素

题目&#xff1a; 题解&#xff1a; class Solution { public:bool check(vector<vector<int>>& matrix, int mid, int k, int n) {int i n - 1;int j 0;int num 0;while (i > 0 && j < n) {if (matrix[i][j] < mid) {num i 1;j;} else…

YOLOv9改进策略【模型轻量化】| MoblieNetV3:基于搜索技术和新颖架构设计的轻量型网络模型

一、本文介绍 本文记录的是基于MobileNet V3的YOLOv9目标检测轻量化改进方法研究。MobileNet V3的模型结构是通过网络搜索得来的&#xff0c;其中的基础模块结合了MobileNet V1的深度可分离卷积、MobileNet V2的线性瓶颈和倒置残差结构以及MnasNet中基于挤压和激励的轻量级注意…

python-Flask搭建简易登录界面

使用Flask框架搭建一个简易的登录界面&#xff0c;登录成功获取token数据 1 搭建简易登录界面 代码如下 from flask import Flask, jsonify from flask import request import time, hashlibapp Flask(__name__)login_html <html> <head> <title>Log…

day7 测试知识积累

1.有一个班级表,里面有学号,姓名,学科,分数。找到语文学科分数最高的前10位的姓名(SQL) select 姓名 from 班级表 where 学科=语文 order by 分数 DESC limit 10; 2.有一张年级表,有班级,年级,学生姓名,找到这10名同学所在的班级(SQL) select class from 年级表 wher…