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

news2024/11/19 6:40:43

内存管理

在这里插入图片描述



定义与作用

在这里插入图片描述

内存池管理

  • 基础定义
    • 内存池是一种管理固定大小内存块的机制,主要用于减少碎片化,提高内存分配效率。
    • 在 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.coloradmin.cn/o/1466663.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【电子书】人工智能

资料 wx&#xff1a;1945423050&#xff0c;备注来源和目的 个人整理了一些互联网电子书 人工智能 Julia机器学习核心编程&#xff1a;人人可用的高性能科学计算.epubKeras深度学习实战.epubMATLAB图像与视频处理实用案例详解.epubMATLAB金融算法分析实战&#xff1a;基于机器…

Android 开发一个耳返程序(录音,实时播放)

本文目录 点击直达 Android 开发一个耳返程序程序编写1. 配置 AndroidManifast.xml2.编写耳返管理器3. 录音权限申请4. 使用注意 最后我还有一句话要说怕相思&#xff0c;已相思&#xff0c;轮到相思没处辞&#xff0c;眉间露一丝 Android 开发一个耳返程序 耳返程序是声音录入…

开源分子对接程序rDock的安装及使用流程

欢迎浏览我的CSND博客&#xff01; Blockbuater_drug …点击进入 前言 本文介绍开源分子对接程序rDock在Linux Ubuntu 22.04系统上的conda安装、编译安装过程及程序使用流程。 一、rDock是什么&#xff1f; rDock来源 rDock是一个快速、多功能的开源对接程序&#xff0c;可用…

鼠标右键助手专业版 MouseBoost PRO for Mac v3.3.6中文破解

MouseBoost Pro mac版是一款简单实用的鼠标右键助手专业版&#xff0c;MouseBoost Pro for Mac只要轻点你的鼠标右键&#xff0c;就可以激活你想要的各种功能&#xff0c;让你的工作效率大幅度提高&#xff0c;非常好用。 软件下载&#xff1a;MouseBoost PRO for Mac v3.3.6中…

Matlab/simulink光伏发电的扰动观察法MPPT仿真(持续更新)

1.光伏发电的电导增量法MPPT仿真 2.光伏发电的恒定电压法MPPT仿真 3.光伏发电的扰动观察法MPPT仿真 4.光伏发电的占空比法MPPT仿真 5.基于神经网络的MPPT光伏发电仿真 6. 基于模糊控制的MPPT光伏发电仿真 7. 基于粒子群算法&#xff08;PSO&#xff09;的500w光伏系统MPPT控…

WordPres Bricks Builder 前台RCE漏洞

免责声明&#xff1a;文章来源互联网收集整理&#xff0c;请勿利用文章内的相关技术从事非法测试&#xff0c;由于传播、利用此文所提供的信息或者工具而造成的任何直接或者间接的后果及损失&#xff0c;均由使用者本人负责&#xff0c;所产生的一切不良后果与文章作者无关。该…

spark 少量key倾斜的join优化

背景 在使用spark join时&#xff0c;我们经常遇到少量key拥有大量的数据而导致的数据倾斜的问题&#xff0c;这导致了task任务数据处理非常不均匀而影响最终时效 少量key数据倾斜的join优化 这里有一个前提&#xff0c;join的另一边的表没有数据倾斜问题&#xff0c;也就是…

问题慢慢解决-通过android emulator调试android kernel-内核条件断点遇到的问题和临时解决方案

起因 在摸索到这个方案之后&#xff0c;mac m1调试aarch64 android kernel最终方案&#xff0c;就准备调试内核了&#xff0c;预备下断点的地方是 b binder_poll b ep_ptable_queue_proc b remove_wait_queue但是由于是android系统&#xff0c;上面三个函数会被频繁的触发&am…

Window部署SkyWalking

SkyWalking mysql的驱动依赖 选择下载版本 v9.4 现在后解压缩目录结构 一、修改config目录文件 application.yml 修改1&#xff1a; selector: ${SW_STORAGE:h2} 修改后&#xff1a; selector: ${SW_STORAGE:mysql} 修改2&#xff1a;使用mysql数据库 mysql: properti…

windows 11+docker desktop+grafana+influxDB

下载安装docker desktop 出现WSL相关的错误。WSL是一个linux内核的子系统&#xff0c;docker是基于linux内核的&#xff0c;所以运行docker需要WSL。 以管理员权限打开powershell&#xff0c;查看WSL状态 wsl --status 我遇到的错误是因为我关闭了windows的某些更新 执行上…

comfyui节点编写示例文件(下)

** 1、先看示例文件的结构 ** ** 2、设置输入参数 ** ** 3、节点指定任务、输出啥 ** ** 4、这个节点干了啥&#xff0c;定义函数、输出结果 ** ** 5、多个节点&#xff0c;就多个类 ** ** 6、设置多个入口 ** ** 7、放置 ** 直接把py文件放到 .\Co…

Python+Selenium-使用Pillow库进行元素截图

1. Pillow库 Pillow库是Python图像处理的基库&#xff0c;是一个免费开源的第三方库。 通过Python PyPi第三方库官网&#xff08;https://pypi.org/project/Pillow/#files&#xff09;下载与平台系统相对应的版本&#xff1a; 下载完成后&#xff0c;进入下载文件的所在位置&…

Redis(十六)缓存预热+缓存雪崩+缓存击穿+缓存穿透

文章目录 面试题缓存预热缓存雪崩解决方案 缓存穿透解决方案 缓存击穿解决方案案例&#xff1a;高并发聚划算业务 总结表格 面试题 缓存预热、雪崩、穿透、击穿分别是什么?你遇到过那几个情况?缓存预热你是怎么做的?如何避免或者减少缓存雪崩?穿透和击穿有什么区别?他两是…

力扣hot100题解(python版7-9题)

7、接雨水 给定 n 个非负整数表示每个宽度为 1 的柱子的高度图&#xff0c;计算按此排列的柱子&#xff0c;下雨之后能接多少雨水。 示例 1&#xff1a; 输入&#xff1a;height [0,1,0,2,1,0,1,3,2,1,2,1] 输出&#xff1a;6 解释&#xff1a;上面是由数组 [0,1,0,2,1,0,1,…

mp4格式是什么?视频如何转换成MP4格式【详解】

当我们谈论数字视频时&#xff0c;MP4无疑是最常见、最受欢迎的格式之一。MP4&#xff0c;全称为MPEG-4 Part 14&#xff0c;是一种多媒体容器格式&#xff0c;主要用于存储音频、视频、字幕和图像等多媒体数据。由于其出色的兼容性、广泛的应用范围以及优秀的压缩效率&#xf…

Conmi的正确答案——将JAVA中maven的.m2文件夹放到D盘

系统&#xff1a;WIN11 1、将.m2文件夹移动到D盘 移动后&#xff1a; 2、创建目录链接 mklink /j "C:\Users\Administrator\.m2" "D:\.m2"至此&#xff0c;maven默认的jar包会加载到D盘的.m2文件夹

【动态规划】【前缀和】【推荐】2463. 最小移动总距离

作者推荐 【广度优先搜索】【网格】【割点】【 推荐】1263. 推箱子 本文涉及知识点 动态规划汇总 C算法&#xff1a;前缀和、前缀乘积、前缀异或的原理、源码及测试用例 包括课程视频 2463. 最小移动总距离 X 轴上有一些机器人和工厂。给你一个整数数组 robot &#xff0c…

计算机组成原理(12)----多处理系统

目录 1.SISD&#xff08;单指令流单数据流&#xff09; &#xff08;1&#xff09;特性 &#xff08;2&#xff09;硬件组成 2.SIMD&#xff08;单指令流多数据流&#xff09; &#xff08;1&#xff09;特性 &#xff08;2&#xff09;硬件组成 3.MISD&#xff08;多指…

【Java EE初阶二十四】servlet的深入理解

1. Servlet API 的学习 下面主要学习这三个类&#xff0c;就已经可以完成 Servlet 的大部分开发了&#xff1b; 1. Httpservlet 2. HttpServletRequest 3. HttpServletResponse 2. Httpservlet的学习 2.1 Httpservlet在tomcat的工作原理 写一个 Servlet 代码&#xff0c;往往都…

C++最佳实践之编译篇

C最佳实践之工程编译 在大型c/c工程开发中&#xff0c;往往会涉及多级CMakeLists.txt的调用&#xff0c;并且调用方式错综复杂&#xff0c;主要有以下两种方式&#xff1a; 1. 子目录中的CMakeList.txt独立生成目标&#xff0c;不作为主目标生成过程的依赖关系&#xff08;比…