RT-Thread-快速入门-3-内存管理

内存管理

在这里插入图片描述



定义与作用

在这里插入图片描述

内存池管理

  • 基础定义
    • 内存池是一种管理固定大小内存块的机制,主要用于减少碎片化,提高内存分配效率。
    • 在 RT-Thread 中,内存池允许用户预分配一定数量的具有相同大小的内存块,应用程序可以从中快速分配和释放内存。
  • 主要内容
    • 创建和初始化内存池:定义一个内存池变量,通过 API 函数初始化,设定内存块大小和数量。
    • 从内存池分配内存:应用程序可以从内存池中请求内存块,用于存储数据。
    • 返回内存至内存池:使用完毕后,应将内存块返回至内存池,以供其他任务或用途重用。

内存堆管理

  • 基础定义

    • 内存堆管理提供更为灵活的内存分配方式,允许按需分配任意大小的内存区块。
    • RT-Thread 支持动态内存分配(如 malloc、free 等标准 C 函数)以及自定义的动态内存管理函数。
  • 主要内容

    • 动态分配和释放内存:通过 rt_malloc()rt_free() 等 API,分配和释放内存。

    • 内存碎片整理:某些情况下,可以通过内存整理来减少内存碎片,提高内存利用率。


举例-通俗

  • 在解释内存管理时,我们可以将其比作 用餐规则。

内存池管理 (Memory Pool Management)

  • 场景

    • 想象你在一个咖啡厅里,这个咖啡厅专门提供一种大小固定的咖啡杯(比如中杯),这些咖啡杯都是提前准备好的,并且放在一个特定的架子上。
    • 顾客来到咖啡厅时,可以快速地从架子上拿一个中杯咖啡。
    • 喝完后,顾客会把咖啡杯还回去,咖啡厅工作人员会清洗这些杯子并重新放回架子上,供下一位顾客使用。
  • 对照关系

    • 这里,咖啡杯相当于内存池管理中的内存块,架子上的所有咖啡杯集合就像是一个内存池。
    • 咖啡杯的统一大小代表内存池中所有内存块的固定大小,而架子上的咖啡杯数量限制类似于内存池的容量。
    • 顾客使用后归还的过程类似于内存块的回收和重用。

内存堆管理 (Heap Management)

  • 场景

    • 现在想象一个不同的场景,在一个大型的自助餐厅,顾客可以根据自己的需要选择不同大小的盘子来装食物。
    • 你可以选择一个小盘子来装沙拉,一个中盘子来装主菜,还可以选择一个大盘子来装水果。
    • 用完之后,你会把盘子放到指定的回收处,餐厅工作人员会清洗这些盘子并把它们放回原位,与内存池管理相比,但这次它们不再是固定大小的集合,而是根据需要被选取和放回的。
  • 对照关系

    • 在这个例子中,不同大小的盘子可以看作是动态分配的内存块,而自助餐厅提供的整体盘子资源类似于内存堆。
    • 顾客根据需求选择不同大小的盘子,就像程序根据需要申请不同大小的内存空间。
    • 用完后归还盘子的过程对应于释放内存空间,以便这些资源可以被其他顾客(即其他程序或进程)再次使用。

总结

  • 内存池管理就像是咖啡厅中预先准备好的一堆固定大小的咖啡杯,适合于需要快速且频繁地分配和回收相同大小资源的场景;
  • 而内存堆管理则类似于自助餐厅里各种大小的盘子,适用于需求多变,需要不同大小内存块的情况。

示例代码

  • 两个代码的实现方式体现了区别,区别在于与存储空间数据交互的过程

  • 内存池
    在这里插入图片描述

  • 内存堆
    在这里插入图片描述


内存池管理

  • 该程序会从内存池中分配内存块,并在每个块中填入从1开始的递增数字。
  • 然后对其进行逐个取用与输出
#include <rtthread.h>  // 引入RT-Thread头文件

#define POOL_SIZE 128   // 定义内存池的大小为128字节
#define BLOCK_SIZE 32   // 定义每个内存块的大小为32字节
#define BLOCK_COUNT 4   // 定义内存块的数量为4(示例中实际可用)

// 定义内存池空间,实际存储内存块的地方
static rt_uint8_t mempool[POOL_SIZE];
// 定义内存池控制块,管理内存池的状态和属性
struct rt_mempool mp;

int main(void)
{
    void *block;   // 定义一个指针用于接收分配的内存块地址
    int i = 1;     // 用于填充内存块的递增数字

    // 初始化内存池
    rt_mp_init(&mp, "mempool", &mempool, sizeof(mempool), BLOCK_SIZE);

    for (int j = 0; j < BLOCK_COUNT; j++) {
        // 从内存池分配一个内存块
        block = rt_mp_alloc(&mp, RT_WAITING_FOREVER);
        if (block != RT_NULL) {
            // 将递增数字填入内存块
            *(int *)block = i++;
            // 打印内存块中的数字,验证我们的操作
            rt_kprintf("Block %d: %d\n", j + 1, *(int *)block);
            // 模拟一些处理过程,这里我们简单地延时
            rt_thread_mdelay(RT_TICK_PER_SECOND);
            // 将内存块返回至内存池,释放内存块以供其他操作使用
            rt_mp_free(block);
        }
    }

    return 0;
}

内存堆管理

  • 在这段代码中,我们循环BLOCK_COUNT次,每次都尝试从堆中分配一块大小足以存储一个整数的内存。
  • 如果分配成功,我们就把一个递增的数字存入这块内存,打印出这个数字,然后在下一次循环前释放这块内存。

  • 请注意,使用堆内存管理时,您需要保证系统的堆大小足够大,能够满足您的分配请求。
  • 您可以在系统初始化代码中设置堆大小。另外,频繁地分配和释放小块内存可能会导致内存碎片,从而影响系统性能。
#include <rtthread.h>  // 引入RT-Thread头文件

#define BLOCK_COUNT 10  // 定义需要分配的内存块数量

int main(void)
{
    void *block;  // 定义一个指针用于接收分配的内存块地址
    int i = 1;    // 用于填充内存块的递增数字

    for (int j = 0; j < BLOCK_COUNT; j++) {
        // 从内存堆中动态分配一块内存
        block = rt_malloc(sizeof(int));
        if (block != RT_NULL) {
            // 将递增数字填入内存块
            *(int *)block = i++;
            // 打印内存块中的数字,验证我们的操作
            rt_kprintf("Block %d: %d\n", j + 1, *(int *)block);
            // 模拟一些处理过程,这里我们简单地延时
            rt_thread_mdelay(RT_TICK_PER_SECOND);
            // 释放内存块,返回它到内存堆
            rt_free(block);
        } else {
            // 如果内存分配失败,打印错误信息
            rt_kprintf("Memory allocation failed for block %d\n", j + 1);
        }
    }

    return 0;
}

逐行解释 代码

内存池管理

  • #include <rtthread.h>: 引入 RT-Thread 的主要功能。
  • #define POOL_SIZE 128: 设置内存池总大小为128字节。
  • #define BLOCK_SIZE 32: 设置每个内存块的大小为32字节。
  • #define BLOCK_COUNT 10: 设定内存块数量为10。
  • static rt_uint8_t mempool[POOL_SIZE]: 静态分配内存池数组。
  • struct rt_mempool mp: 定义内存池控制块。
  • int main(void): 主函数开始。
  • void *block: 定义指向内存块的指针。
  • rt_mp_init: 初始化内存池。
  • 循环中,rt_mp_alloc从内存池分配内存,rt_kprintf打印信息,rt_thread_mdelay延时,rt_mp_free释放内存。
#include <rtthread.h>  // 引入 RT-Thread 的主要头文件,提供操作系统功能
#define POOL_SIZE 128  // 定义内存池的大小为128字节
#define BLOCK_SIZE 32  // 定义每个内存块的大小为32字节
#define BLOCK_COUNT 10 // 定义内存池能够容纳的内存块数量为10(注意:此处定义并未直接用于下面的代码,但有助于理解内存池的容量)

static rt_uint8_t mempool[POOL_SIZE]; // 静态分配128字节内存作为内存池的存储空间
struct rt_mempool mp; // 声明一个内存池控制块变量

int main(void)
{
    void *block; // 用于接收分配的内存块地址的指针

    // 初始化内存池,参数分别为:内存池控制块地址、内存池名称、内存池的存储空间地址、内存池的总大小、每个内存块的大小
    rt_mp_init(&mp, "mempool", &mempool, sizeof(mempool), BLOCK_SIZE);

    // 循环体:模拟内存块的分配和使用
    while(1)
    {
        block = rt_mp_alloc(&mp, RT_WAITING_FOREVER); // 从内存池中分配一个内存块,如果没有可用内存块则永久等待
        if (block != RT_NULL) // 检查是否成功分配内存块
        {
            // ... 在这里使用内存块进行操作 ...

            rt_kprintf("Block allocated\n"); // 打印内存块已被分配的信息
            rt_thread_mdelay(1000); // 线程延迟1000毫秒(1秒)
            rt_mp_free(block); // 将内存块归还给内存池
        }
    }
    // 实际应用中不会到达这里,但理论上应释放所有资源
    return 0; // 返回0,结束主函数
}


内存堆管理

  • #include <rtthread.h>: 引入 RT-Thread 的头文件。
  • #define BLOCK_COUNT 10: 定义需要处理的内存块数量。
  • int main(void): 主函数入口。
  • void *block: 定义一个通用指针用于指向分配的内存块。
  • int i = 1: 初始化递增的数字。\
  • 循环使用rt_malloc从堆中分配内存,存储数字并打印,然后用rt_free释放内存。
  • rt_device_find, rt_device_open, rt_mp_init, rt_mp_alloc, rt_mp_free, rt_thread_mdelay等函数分别用于设备查找、打开、内存分配与释放及线程延时。
#include <rtthread.h>  // 引入 RT-Thread 的主要头文件

int main(void)
{
    void *block; // 定义一个指针,用于指向分配的内存块
    int i = 1;   // 定义一个整数变量,用于在内存块中存储递增的数字

    while(1)
    {
        block = rt_malloc(sizeof(int)); // 从堆中分配足够存储一个整数的内存块
        if (block != RT_NULL) // 检查内存块是否成功分配
        {
            *(int *)block = i; // 将递增的数字存储在分配的内存块中
            rt_kprintf("Allocated int: %d\n", *(int *)block); // 打印存储在内存块中的数字

            i++; // 递增数字
            rt_thread_mdelay(1000); // 线程延迟1000毫秒(1秒)
            rt_free(block); // 释放内存块,将其归还给堆
        }
    }
    // 在实际的应用程序中,这里应该有代码来清理和释放所有分配的资源
    return 0; // 返回0,正常结束主函数
}


在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【Java程序设计】【C00287】基于Springboot的疫情防控期间某村外出务工人员管理系统(有论文)

基于Springboot的疫情防控期间某村外出务工人员管理系统&#xff08;有论文&#xff09; 项目简介项目获取开发环境项目技术运行截图 项目简介 这是一个基于Springboot的疫情防控期间某村外出务工人员信息管理系统 本系统分为系统功能模块、管理员功能模块、用户功能模块、采集…

第三百六十五回

文章目录 1. 概念介绍2. 方法与信息2.1 获取方法2.2 详细信息 3. 示例代码4. 内容总结 我们在上一章回中介绍了"如何获取设备信息"相关的内容&#xff0c;本章回中将介绍如何获取App自身的信息.闲话休提&#xff0c;让我们一起Talk Flutter吧。 1. 概念介绍 我们在本…

C++的vector容器->基本概念、构造函数、赋值操作、容量和大小、插入和删除、数据存取、互换容器、预留空间

#include<iostream> using namespace std; #include <vector> //vector容器构造 void printVector(vector<int>& v) { for (vector<int>::iterator it v.begin(); it ! v.end(); it) { cout << *it << " "…

Redis中的rdb和aof

Redis中的rdb和aof 持久化流程RDB机制redis.conf中rdb的配置save bgsave 自动化 rdb触发的三种方式save 命令bgsave命令自动触发 rdb的优势劣势 AOFaof原理aof配置文件重写原理aof的三种触发机制 appendfsyncaof fix工具 redis-check-aof练习aofaof的优缺点 redis是一个内存数据…

GEE必须会教程—Map工具的使用

一个星期的时间&#xff0c;跟着小编的角度&#xff0c;我们已经学习了数值、字符串、字典、列表、日期、矩阵等基本的编程数据类型&#xff0c;这些是学习任何一门编程语言都需要掌握的知识&#xff0c;还有不懂得赶紧关注小编&#xff0c;进行主页查看过往文章&#xff01;! …

[rust] 11 所有权

文章目录 一 背景二 Stack 和 Heap2.1 Stack2.2 Heap2.3 性能区别2.4 所有权和堆栈 三 所有权原则3.1 变量作用域3.2 String 类型示例 四 变量绑定背后的数据交互4.1 所有权转移4.1.1 基本类型: 拷贝, 不转移所有权4.1.2 分配在 Heap 的类型: 转移所有权 4.2 Clone(深拷贝)4.3 …

可变参数、Collections类

一、可变参数 定义&#xff1a;是一种特殊的形参&#xff0c;定义在方法、构造器的形参列表里 格式&#xff1a;数据类型...参数名称 特点&#xff1a;可以不传数据&#xff0c;也可以传一个或者多个数据给它&#xff0c;也可以传一个数组 好处&#xff1a;可以灵活接收数据…

牛客网 HJ34 图片整理

思路&#xff1a; 题目总共涉及三种类型的字符&#xff1a;大写字母&#xff0c;小写字母&#xff0c;数字 我们可以简单归纳为两类&#xff1a;字母类和数字类&#xff08;采用isalpha和isdigit来判断&#xff09;&#xff0c;创建两个数组来保存这两类字符 因为题目要求按…

图片Base64编码解码的优缺点及应用场景分析

title: 图片Base64编码解码的优缺点及应用场景分析 date: 2024/2/24 14:24:37 updated: 2024/2/24 14:24:37 tags: 图片Base64编码解码HTTP请求优化网页性能加载速度安全性缓存机制 随着互联网的迅猛发展&#xff0c;图片在网页和移动应用中的使用越来越广泛。而图片的传输和加…

【新手易错点】golang中byte和rune

1 总体区别 在Golang中&#xff0c;byte和rune是两种不同类型的数据。简单来说&#xff0c;byte是一个8位的无符号整数类型&#xff0c;而rune则是一个32位的Unicode字符类型。 Byte: 在Golang中&#xff0c;byte类型实际上是uint8的别名&#xff0c;它用来表示8位的无符号整…

【MySQL】连接查询和自连接的学习和总结

&#x1f308;个人主页: Aileen_0v0 &#x1f525;热门专栏: 华为鸿蒙系统学习|计算机网络|数据结构与算法 ​&#x1f4ab;个人格言:“没有罗马,那就自己创造罗马~” #mermaid-svg-x4sPmqTXA4yupW1n {font-family:"trebuchet ms",verdana,arial,sans-serif;font-siz…

【Linux】C语言实现超级简单进度条!你不会还不知道吧?

目录 1. 基础准备&#x1f38d; 1.1 \r&&\n 1.2 缓冲区 2. 进度条1.0&#x1f940; 2.1 Process.h 2.2 Process.c 2.3 Main.c 2.4 Makefile 3.进度条 2.0&#x1faba; 3.1 Process.h 3.2 Process.c 3.3 Main.c 1. 基础准备&#x1f38d; 1.1 \r&&…

MobaXterm连接VirtualBox虚拟机

目录 1.下载MobaXterm 2.获取连接配置 3.mobaXterm连接虚拟机 4.更好的方案 1.下载MobaXterm 据说MobaXtrem是远程终端的超级全能神器,官网下载地址&#xff1a;MobaXterm free Xserver and tabbed SSH client for Windows 选择适合你的版本&#xff1a;一个是Home Editi…

apidoc接口文档的自动更新与发布

文章目录 一、概述二、环境准备三、接口文档生成1. 下载源码2. 初始化3.执行 四、文档发布五&#xff0c;配置定时运行六&#xff0c;docker运行 一、概述 最近忙于某开源项目的接口文档整理&#xff0c;采用了apidoc来整理生成接口文档。 apidoc是一个可以将源代码中的注释直…

数据结构D4作业

1.实现单向循环链表的功能 loop.c #include "loop.h" loop_p create_loop() { loop_p H(loop_p)malloc(sizeof(loop)); if(HNULL) { printf("创建失败\n"); return NULL; } H->len0; H->nextH; ret…

Android进阶之旅(第5天)

充实的一天又过去了&#xff0c;今天真的好冷啊&#xff0c;我们这里雪很大&#xff0c;早上最傻逼的决定就是穿了一个短的棉袜出来&#xff0c;漏脚踝&#xff0c;冷成傻子 接下来老规矩&#xff0c;看下昨天计划的完成情况&#xff1a; 今日计划&#xff1a; 1.过bug 2.看…

CentOS7 安装Python3.8

在 CentOS 7 上&#xff0c;按照以下步骤安装 Python 3.8&#xff1a; 添加EPEL仓库&#xff1a;首先安装 EPEL&#xff08;Extra Packages for Enterprise Linux&#xff09;仓库 sudo yum install epel-release安装Software Collections (SCL)仓库&#xff1a;随后&#xff0…

搭建私有Git服务器:GitLab部署详解

引言&#xff1a; 为了方便团队协作和代码管理&#xff0c;许多组织选择搭建自己的私有Git服务器。GitLab是一个集成了Git版本控制、项目管理、代码审查等功能的开源平台&#xff0c;是搭建私有Git服务器的理想选择。 目录 引言&#xff1a; 一、准备工作 在开始部署GitLab之…

更新至2022年世界各国数字经济发展相关指标(23个指标)

更新至2022年世界各国数字经济发展相关指标&#xff08;23个指标&#xff09; 1、时间&#xff1a;具体指标时间见下文 2、来源&#xff1a;WDI、世界银行、WEF、UNCTAD、SJR、国际电联 3、指标&#xff1a;移动网络覆盖率&#xff08;2000-2022&#xff09;、固定电话普及率…

Code-Audit(代码审计)习题记录6-7

介绍&#xff1a; 自己懒得搭建靶场了&#xff0c;靶场地址是 GitHub - CHYbeta/Code-Audit-Challenges: Code-Audit-Challenges为了方便在公网练习&#xff0c;可以随地访问&#xff0c;本文所有的题目均来源于网站HSCSEC-Code Audit 6、习题6 题目内容如下&#xff1a; 源代…