内存管理(SRAM)

news2024/12/23 11:45:07

内存管理介绍

内存管理实际上就是指管理SRAM.
内存管理,是指软件运行时对计算机内存资源的分配和使用的技术。其最主要的目的是如
何高效、快速的分配,并且在适当的时候释放和回收内存资源。内存管理的实现方法有很多种,其实最终都是要实现两个函数:malloc 和 free。malloc 函数用来内存申请,free 函数用于内存释放。

本章,我们介绍一种比较简单的办法来实现:分块式内存管理。下面我们介绍一下该方法
的实现原理,如下图 所示:
在这里插入图片描述
从上图可以看出,分块式内存管理由内存池和内存管理表两部分组成。内存池被等分为了
n 块,对应的内存管理表,大小也为 n,内存管理表的每一个项对应内存池的一块内存。
内存管理表的项值代表的意义为:当该项值为 0 的时候,代表对应的内存块未被占用,当
该项值非零的时候,代表该项对应的内存块已经被占用,其数值则代表被连续占用的内存块数。
比如某项值为 10,那么说明包括本项对应的内存块在内,总共分配了 10 个内存块给外部的某个指针。内存分配方向如上图所示,是从顶→底的分配方向。即首先从最末端开始找空内存。当内存管理刚初始化的时候,内存表全部清零,表示没有任何内存块被占用。

分配原理

当指针 p 调用 malloc 申请内存的时候,先判断 p 要分配的内存块数(m),然后从第 n 开始,向下查找,直到找到 m 块连续的空内存块(即对应内存管理表项为 0),然后将这 m 个内存管理表项的值都设置为 m(标记被占用),最后,把最后的这个空内存块的地址返回指针 p,完成一次分配。注意:如果当内存不够的时候(找到最后也没有找到连续 m 块空闲内存),则返回 NULL 给 p,表示分配失败

释放原理

当 p 申请的内存用完,需要释放的时候,调用 free 函数实现。free 函数先判断 p 指向的内存地址所对应的内存块,然后找到对应的内存管理表项目,得到 p 所占用的内存块数目 m(内存管理表项目的值就是所分配内存块的数目),将这 m 个内存管理表项目的值都清零,标记释放,完成一次内存释放。

核心代码

malloc.h中比较重要的代码

/* mem1 内存参数设定.mem1 是 F103 内部的 SRAM. */
#define MEM1_BLOCK_SIZE 32
/* 内存块大小为 32 字节 */
701
正点原子精英 STM32F103 开发板教程
STM32F103 开发指南
#define MEM1_MAX_SIZE 40 * 1024 /* 最大管理内存 40K, F103ZE 内部 SRAM 总共 512KB */
#define MEM1_ALLOC_TABLE_SIZE MEM1_MAX_SIZE/MEM1_BLOCK_SIZE /* 内存表大小 */
/* mem2 内存参数设定.mem3 是 F103 外扩 SRAM */
#define MEM2_BLOCK_SIZE
32
/* 内存块大小为 32 字节 */
#define MEM2_MAX_SIZE 1 * 32
/* 精英板没有外扩内存,故设置一个最小值 */
#define MEM2_ALLOC_TABLE_SIZE MEM2_MAX_SIZE/MEM2_BLOCK_SIZE /* 内存表大小 */
/* 内存管理控制器 */
struct _m_mallco_dev
{
void (*init)(uint8_t);
/* 初始化 */
uint16_t (*perused)(uint8_t); /* 内存使用率 */
uint8_t *membase[SRAMBANK]; /* 内存池 管理 SRAMBANK 个区域的内存 */
MT_TYPE *memmap[SRAMBANK]; /* 内存管理状态表 */
uint8_t memrdy[SRAMBANK]; /* 内存管理是否就绪 */
};

根据上面所列的宏定义,那么此时总的内存池分配的大小size(内存池+内存分配管理表):

size = MEM1_MAX_SIZE + (MEM1_MAX_SIZE / MEM1_BLOCK_SIZE) * sizeof(MT_TYPE)

式子可变形为:

MEM1_MAX_SIZE = (MEM1_BLOCK_SIZE * size) / (MEM1_BLOCK_SIZE + sizeof(MT_TYPE))

假设一款单片机的SRAM为64KB,那么我们应该选取合理的大小作为内存池分配的大小。按上述的malloc.h中配置,可以算出

size= 40 * 1024 + (40 * 1024 / 32) * 2 = 43520 = 42.5KB

看以到42.5KB<64KB,这是为了留有一定的空间存储其他全局变量 / 数组

malloc函数

在这里插入图片描述

/**
 * @brief       内存分配(内部调用)
 * @param       memx : 所属内存块
 * @param       size : 要分配的内存大小(字节)
 * @retval      内存偏移地址
 *   @arg       0 ~ 0XFFFFFFFE : 有效的内存偏移地址
 *   @arg       0XFFFFFFFF     : 无效的内存偏移地址
 */
static uint32_t my_mem_malloc(uint8_t memx, uint32_t size)
{
    signed long offset = 0;
    uint32_t nmemb;     /* 需要的内存块数 */
    uint32_t cmemb = 0; /* 连续空内存块数 */
    uint32_t i;

    if (!mallco_dev.memrdy[memx])
    {
        mallco_dev.init(memx);          /* 未初始化,先执行初始化 */
    }
    
    if (size == 0) return 0XFFFFFFFF;   /* 不需要分配 */

    nmemb = size / memblksize[memx];    /* 获取需要分配的连续内存块数 */

    if (size % memblksize[memx]) nmemb++;

    for (offset = memtblsize[memx] - 1; offset >= 0; offset--)  /* 搜索整个内存控制区 */
    {
        if (!mallco_dev.memmap[memx][offset])
        {
            cmemb++;            /* 连续空内存块数增加 */
        }
        else 
        {
            cmemb = 0;          /* 连续内存块清零 */
        }
        
        if (cmemb == nmemb)     /* 找到了连续nmemb个空内存块 */
        {
            for (i = 0; i < nmemb; i++) /* 标注内存块非空 */
            {
                mallco_dev.memmap[memx][offset + i] = nmemb;
            }

            return (offset * memblksize[memx]); /* 返回偏移地址 */
        }
    }

    return 0XFFFFFFFF;  /* 未找到符合分配条件的内存块 */
}

/**
 * @brief       分配内存(外部调用)
 * @param       memx : 所属内存块
 * @param       size : 要分配的内存大小(字节)
 * @retval      分配到的内存首地址.
 */
void *mymalloc(uint8_t memx, uint32_t size)
{
    uint32_t offset;
    offset = my_mem_malloc(memx, size);

    if (offset == 0XFFFFFFFF)   /* 申请出错 */
    {
        return NULL;            /* 返回空(0) */
    }
    else    /* 申请没问题, 返回首地址 */
    {
        return (void *)((uint32_t)mallco_dev.membase[memx] + offset);
    }
}

free函数

在这里插入图片描述

/**
 * @brief       释放内存(内部调用)
 * @param       memx   : 所属内存块
 * @param       offset : 内存地址偏移
 * @retval      释放结果
 *   @arg       0, 释放成功;
 *   @arg       1, 释放失败;
 *   @arg       2, 超区域了(失败);
 */
static uint8_t my_mem_free(uint8_t memx, uint32_t offset)
{
    int i;

    if (!mallco_dev.memrdy[memx])   /* 未初始化,先执行初始化 */
    {
        mallco_dev.init(memx);
        return 1;                   /* 未初始化 */
    }

    if (offset < memsize[memx])     /* 偏移在内存池内. */
    {
        int index = offset / memblksize[memx];      /* 偏移所在内存块号码 */
        int nmemb = mallco_dev.memmap[memx][index]; /* 内存块数量 */

        for (i = 0; i < nmemb; i++)                 /* 内存块清零 */
        {
            mallco_dev.memmap[memx][index + i] = 0;
        }

        return 0;
    }
    else
    {
        return 2;   /* 偏移超区了. */
    }
}

/**
 * @brief       释放内存(外部调用)
 * @param       memx : 所属内存块
 * @param       ptr  : 内存首地址
 * @retval      无
 */
void myfree(uint8_t memx, void *ptr)
{
    uint32_t offset;

    if (ptr == NULL)return;     /* 地址为0. */

    offset = (uint32_t)ptr - (uint32_t)mallco_dev.membase[memx];
    my_mem_free(memx, offset);  /* 释放内存 */
}

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

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

相关文章

用vscode仿制小米官网

html内容: <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>Document</title><link rel&quo…

无线基本认识和配置

1、无线局域网 IEEE 802.11标准 根据应用范围分类 WPAN --- 个人无线网络 NFC、ZIgbee、Bluetooth WLAN --- 无线局域网 WiFi&#xff0c;使用到WPAN技术 WMAN --- 无线城域网 WiMax 802.16 WWAN --- 无线广域网 GSM、CDMA、WCDMA、LTE、5G、TD-SCDMA 2、…

PG 中的 MAXALIGN 及对齐分配内存(MemoryContextAllocAligned)

在PG源码中&#xff0c;MAXALIGN这个宏&#xff0c;返回最接近输入数字&#xff08;大于&#xff09;且能整除8的数&#xff0c;仅此而已。 常用于内存相关的计算&#xff0c;在PG代码中使用的相当广泛&#xff0c;为啥要用这个MAXALIGN&#xff1f;我估计是基于 “CPU访问对齐…

数据库同步方案Sqlserver

数据库同步方案探究 随着信息技术的迅猛发展&#xff0c;数据库在各个领域的应用日益广泛。而在分布式系统、云计算、大数据等场景下&#xff0c;数据库同步成为了一个至关重要的问题。数据库同步不仅关乎数据的完整性和一致性&#xff0c;还直接影响到系统的稳定性和性能。因…

加薪非要老总批?--责任链模式

1.1 老板&#xff0c;我要加薪 "我和刚进来的几个同事比较&#xff0c;我觉得我做得很好。公司每每分配的任务&#xff0c;我基本都可以快速完成。有一次&#xff0c;一段程序需要增加一个分支条件&#xff0c;我立刻想到利用反射、工厂等设计模式来处理&#xff0c;经理对…

移除元素 -- 力扣第27题 -- 暴力、双指针解法

题目 https://leetcode.cn/problems/remove-element/description/ 给你一个数组 nums 和一个值 val&#xff0c;你需要 原地 移除所有数值等于 val 的元素&#xff0c;并返回移除后数组的新长度。 不要使用额外的数组空间&#xff0c;你必须仅使用 O(1) 额外空间并原地修改输…

Maven--lib分离的打包方式

就是把lib包和source源码分开打包。优势就是&#xff0c;面对频繁更新的应用场景时&#xff0c;可以只更新源码包&#xff08;当然&#xff0c;前提是你的依赖没有增减&#xff09;。尤其是使用jenkins更新项目时&#xff0c;会省去很多时间吧&#xff1f; 不同项目的 lib之间不…

yolov9直接调用zed相机实现三维测距(python)

yolov9直接调用zed相机实现三维测距&#xff08;python&#xff09; 1. 相关配置2. 相关代码2.1 相机设置2.2 测距模块2.2 实验结果 相关链接 此项目直接调用zed相机实现三维测距&#xff0c;无需标定&#xff0c;相关内容如下&#xff1a; 1. yolov4直接调用zed相机实现三维测…

传统海外仓的管理模式有什么缺点?使用位像素海外仓系统的海外仓有什么优势?

传统的海外仓管理模式主要需要大量的人工操作和相对简单的信息化手段进行仓库的日常运营。因此&#xff0c;传统海外仓的运作比较依赖仓库员工的手工记录、核对和处理各种仓储和物流信息。 然而&#xff0c;传统海外仓管理模式通常存在一些缺点&#xff1a; 效率低下 因为需…

【数据结构】红黑树详解

目录 前言&#xff1a; 红黑树的概念&#xff1a; 红黑树的性质: 红黑树节点的定义&#xff1a; 红黑树的插入&#xff1a; 情况1&#xff1a;cur为红&#xff0c;p为红&#xff0c;g为黑&#xff0c;u存在且为红 情况2&#xff1a;cur为红&#xff0c;p为红&#xff0c…

数据同步工具datax安装配置与示例

文章目录 一、部署步骤1、jdk环境2、python环境步骤一&#xff1a;安装方式一&#xff1a;官网下载安装包方式二&#xff1a;brew命令安装 步骤二&#xff1a;配置环境变量步骤三&#xff1a;验证 3、maven环境&#xff08;可选&#xff09; 二、下载安装datax1、下载datax源码…

CLCD 流水线发布SpringBoot项目

目录 一、流水线 1.1 点击进入流水线 1.2 新建流水线 二、添加流水线 三、构建上传和构建镜像 ​编辑 四、Docker部署 一、流水线 1.1 点击进入流水线 1.2 新建流水线 二、添加流水线 三、构建上传和构建镜像 在构建上传里添加一个步骤&#xff1a;构建镜像&#xff0c;这…

【环境变量】基本概念理解 | 查看环境变量echo | PATH的应用和修改

目录 前言 基本概念&理解 注意的点 查看环境变量的方法 PATH环境变量 PTAH应用系统指令 PTAH应用用户程序 命令行参数的修改&#xff08;内存级&#xff09; 配置文件的修改 windows环境变量 大家天天开心&#x1f642; bash进程的流程。环境变量在系统指…

实战经验,公众号选题方向大盘点!

公众号是重要的内容传播平台&#xff0c;每个品牌都有自己的公众号&#xff0c;公众号选题选得好不好&#xff0c;直接决定你这篇文章是否会爆&#xff0c;公众号的选题决定了文章的阅读量和粉丝增长数量。一个好的选题带来的利益是多方面的。 选题是每个品牌和企业绞尽脑汁去…

background背景图参数边渐变CSS中创建背景图像的渐变效果

效果:可以看到灰色边边很难受,希望和背景融为一体 原理: 可以使用线性渐变&#xff08;linear-gradient&#xff09;或径向渐变&#xff08;radial-gradient&#xff09;。以下是一个使用线性渐变作为背景图像 代码: background: linear-gradient(to top, rgba(255,255,255,0)…

【Unity每日一记】如何从0到1将特效图集制作成一个特效

&#x1f468;‍&#x1f4bb;个人主页&#xff1a;元宇宙-秩沅 &#x1f468;‍&#x1f4bb; hallo 欢迎 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! &#x1f468;‍&#x1f4bb; 本文由 秩沅 原创 &#x1f468;‍&#x1f4bb; 收录于专栏&#xff1a;Uni…

Flink常见面试问题(附答案)

目录 基础篇1. 什么是Apache Flink&#xff1f;2. Flink与Hadoop的区别是什么&#xff1f;3. Flink中的事件时间&#xff08;Event Time&#xff09;和处理时间&#xff08;Processing Time&#xff09;有什么区别&#xff1f;4. Flink的容错机制是如何实现的&#xff1f;5. 什…

Myelsa的Python函数之旅(高铁直达)

一、函数的定义&#xff1a; 函数(Function)是一段可重复使用的代码块&#xff0c;用于执行特定的任务或计算&#xff0c;并可以接受输入参数和返回输出结果。函数可以将复杂的问题分解为更小的子问题&#xff0c;提高代码的可读性和可维护性。 二、函数的组成&#xff1a; 在…

设计模式总结-适配器模式

适配器模式 模式动机模式定义模式结构适配器模式实例与解析实例一&#xff1a;仿生机器人实例二&#xff1a;加密适配器 总结 模式动机 在软件开发中采用类似于电源适配器的设计和编码技巧被称为适配器模式。 通常情况下&#xff0c;客户端可以通过目标类的接口访问它所提供的…