liteos内存(三)

1. 概述

1.1 基本概念

内存管理模块管理系统的内存资源,它是操作系统的核心模块之一。主要包括内存的初始化、分配以及释放。

在系统运行过程中,内存管理模块通过对内存的申请/释放操作,来管理用户和OS对内存的使用,使内存的利用率和使用效率达到最优,同时最大限度地解决系统的内存碎片问题。

Huawei LiteOS的内存管理分为静态内存管理和动态内存管理,提供内存初始化、分配、释放等功能。

  • 动态内存:在动态内存池中分配用户指定大小的内存块。
    • 优点:按需分配。
    • 缺点:内存池中可能出现碎片。
  • 静态内存:在静态内存池中分配用户初始化时预设(固定)大小的内存块。
    • 优点:分配和释放效率高,静态内存池中无碎片。
    • 缺点:只能申请到初始化预设大小的内存块,不能按需申请。

1.2 动态内存运作机制

动态内存管理,即在内存资源充足的情况下,从系统配置的一块比较大的连续内存(内存池),根据用户需求,分配任意大小的内存块。当用户不需要该内存块时,又可以释放回系统供下一次使用。

与静态内存相比,动态内存管理的好处是按需分配,缺点是内存池中容易出现碎片。

系统动态内存管理结构如图1所示:

第一部分:堆内存(也称内存池)的起始地址及堆区域总大小

第二部分:本身是一个数组,每个元素是一个双向链表,所有free节点的控制头都会被分类挂在这个数组的双向链表中。

假设内存允许的最小节点为2^min字节,则数组的第一个双向链表存储的是所有size为2^min<size< 2^min+1的free节点,第二个双向链表存储的是所有size为2^min+1<size< 2^min+2的free节点,依次类推第n个双向链表存储的是所有size为2^min+n-1<size< 2^min+n的free节点。(这个有点像buddy算法)每次申请内存的时候,会从这个数组检索最合适大小的free节点,进行分配内存。每次释放内存时,会将该片内存作为free节点存储至这个数组,以便下次再利用。

第三部分:占用内存池极大部分的空间,是用于存放各节点的实际区域。以下是LOS_MEM_DYN_NODE节点结构体申明以及简单介绍:

typedef struct tag LOS_MEM_DYN_NODE
{
LOS_DL_LIST stFreeNodeInfo;
struct tagLOS_MEM_DYN_NODE *pstPreNode;
UINT32 uwSizeAndFlag;
}LOS_MEM_DYN_NODE;

1.3 静态内存运作机制

静态内存实质上是一块静态数组,静态内存池内的块大小在初始化时设定,初始化后块大小不可变更。

静态内存池由一个控制块和若干相同大小的内存块构成。控制块位于内存池头部,用于内存块管理。内存块的申请和释放以块大小为粒度。

图 3-4 静态内存示意图

2. 动态内存

2.1 开发指导

2.1.1 使用场景

内存管理的主要工作是动态的划分并管理用户分配好的内存区间。

动态内存管理主要是在用户需要使用大小不等的内存块的场景中使用。

当用户需要分配内存时,可以通过操作系统的动态内存申请函数索取指定大小内存块,一旦使用完毕,通过动态内存释放函数归还所占用内存,使之可以重复使用。

2.1.2 功能

Huawei LiteOS系统中的动态内存管理模块为用户提供下面几种功能,具体的API详见接口手册。

功能分类

接口名

描述

内存初始化

LOS_MemInit

初始化一块指定的动态内存池,大小为size。

申请动态内存

LOS_MemAlloc

从指定动态内存池中申请size长度的内存。

释放动态内存

LOS_MemFree

释放已申请的内存。

重新申请内存

LOS_MemRealloc

按size大小重新分配内存块,并保留原内存块内容。

内存对齐分配

LOS_MemAllocAlign

从指定动态内存池中申请长度为size且地址按boundary字节对齐的内存。

获取内存大小

LOS_MemPoolSizeGet

获取指定的动态内存池总大小

获取内存大小

LOS_MemTotalUsedGet

获取指定动态内存池的总使用量大小

获取内存块数量

LOS_MemFreeBlksGet

获取指定内存池的空闲内存块数量

获取内存块数量

LOS_MemUsedBlksGet

获取指定内存池的已使用的内存块数量

获取分配指定内存区域的任务ID

LOS_MemTaskIdGet

获取分配了指定内存区域的任务ID

获取最后节点内存大小

LOS_MemLastNodeGet

获取除大小为零的终端节点之外的最后一个节点的内存大小

获取内存结构信息

LOS_MemInfoGet

获取指定内存池的内存结构信息

对指定内存池做完整性检查

LOS_MemIntegrityCheck

对指定内存池做完整性检查

获取节点大小

LOS_MemNodeSizeCheck

获取节点的总大小和可操作大小

设定内存检查级别

LOS_MemCheckLevelSet

设定内存检查级别

获取内存检查级别

LOS_MemCheckLevelGet

获取内存检查级别

2.1.3 开发流程

  1. 配置:
  • OS_SYS_MEM_ADDR:系统动态内存池起始地址,一般不需要修改
  • OS_SYS_MEM_SIZE:系统动态内存池大小,以byte为单位,系统默认分配DDR后未使用的空间
  • LOSCFG_BASE_MEM_NODE_INTEGRITY_CHECK:内存越界检测开关,默认关闭。打开后,每次申请动态内存时执行动态内存块越界检查;每次释放静态内存时执行静态内存块越界检查。
  1. 初始化LOS_MemInit。

初始一个内存池后如图,生成一个 EndNode,并且剩余的内存全部被标记为FreeNode节点。注: EndNode作为内存池末尾的节点, size为0。

  1. 申请任意大小的动态内存LOS_MemAlloc。

判断动态内存池中是否存在申请量大小的空间,若存在,则划出一块内存块,以指针形式返回,若不存在,返回NULL。

调用三次LOS_MemAlloc函数可以创建三个节点,假设名称分别为UsedA, UsedB,UsedC,大小分别为sizeA, sizeB, sizeC。因为刚初始化内存池的时候只有一个大的FreeNode,所以这些内存块是从这个FreeNode中切割出来的。

当内存池中存在多个FreeNode的时候进行malloc,将会适配最合适大小的FreeNode。用来新建内存块,减少内存碎片。若新建的内存块不等于被使用的FreeNode的大小,则在新建内存块后,多余的内存又会被标记为一个新的FreeNode。

  1. 释放动态内存LOS_MemFree。

回收内存块,供下一次使用。

假设调用LOS_MemFree释放内存块UsedB,则会回收内存块UsedB,并且将其标记为FreeNode

2.1.4 平台差异性

2.2 编程实例

2.2.1 实例描述

Huawei LiteOS运行期间,用户需要频繁的使用内存资源,而内存资源有限,必须确保将有限的内存资源分配给急需的程序,同时释放不用的内存。

通过Huawei LiteOS内存管理模块可以保证高效、正确的申请、释放内存。

本实例执行以下步骤:

  1. 初始化一个动态内存池。
  2. 在动态内存池中申请一个内存块。
  3. 使用这块内存块存放一个数据。
  4. 打印出存放在内存块中的数据。
  5. 释放掉这块内存。

2.2.2 编程实例

VOID los_memory_test() {
    UINT32 *p_num = NULL;
    UINT32 uwRet;
    uwRet = LOS_MemInit(m_aucSysMem0, 32);
    if (LOS_OK == uwRet) {
        dprintf("内存池初始化成功!\n");
    }
    else {
        dprintf("内存池初始化失败!\n");
        return;
    }
    /*分配内存*/
    p_num = (int*)LOS_MemAlloc(m_aucSysMem0, 4);
    if (NULL == p_num) {
        dprintf("内存分配失败!\n");
        return;
    }
    dprintf("内存分配成功\n");
    /*赋值*/
    *p_num = 828;
    dprintf("*p_num = %d\n", *p_num);
    /*释放内存*/
    uwRet = LOS_MemFree(m_aucSysMem0, p_num);
    if (LOS_OK == uwRet) {
        dprintf("内存释放成功!\n");
    }
    else {
        dprintf("内存释放失败!\n");
    }
    return;
}

2.2.3 结果验证

图 3-5 结果显示

3. 静态内存

3.1 开发指导

当用户需要使用固定长度的内存时,可以使用静态内存分配的方式获取内存,一旦使用完毕,通过静态内存释放函数归还所占用内存,使之可以重复使用。

3.2 功能

Huawei LiteOS的静态内存管理主要为用户提供以下功能。

功能分类

接口名

描述

初始化静态内存

LOS_MemboxInit

初始化一个静态内存池,设定其起始地址、总大小及每个块大小

清除静态内存内容

LOS_MemboxClr

清零静态内存块

申请一块静态内存

LOS_MemboxAlloc

申请一块静态内存块

释放内存

LOS_MemboxFree

释放一个静态内存块

3.3 开发流程

本节介绍使用静态内存的典型场景开发流程。

  1. 规划一片内存区域作为静态内存池。
  2. 调用LOS_MemboxInit接口。

系统内部将会初始化静态内存池。将入参指定的内存区域分割为N块(N值取决于 静态内存总大小和块大小),将所有内存块挂到空闲链表,在内存起始处放置控 制头。

  1. 调用LOS_MemboxAlloc接口。

系统内部将会从空闲链表中获取第一个空闲块,并返回该块的用户空间地址。

  1. 调用LOS_MemboxFree接口。

将该块内存加入空闲块链表。

  1. 调用LOS_MemboxClr接口。

系统内部清零静态内存块,将入参地址对应的内存块清零

3.3 编程实例

Huawei LiteOS运行期间,用户需要频繁的使用内存资源,而内存资源有限,必须确保将有限的内存资源分配给急需的程序,同时释放不用的内存。

通过内存管理模块可以保证正确且高效的申请释放内存。

本实例执行以下步骤:

  1. 初始化一个静态内存池。
  2. 从静态内存池中申请一块静态内存。
  3. 使用这块内存块存放一个数据。
  4. 打印出存放在内存块中的数据。
  5. 清除内存块中的数据。
  6. 释放掉这块内存;
VOID los_membox_test(void) {
    UINT32 *p_num = NULL;
    UINT32 uwBlkSize = 10, uwBoxSize = 100;
    UINT32 uwRet;
    UINT32 pBoxMem[1000];
    uwRet = LOS_MemboxInit(&pBoxMem[0], uwBoxSize, uwBlkSize);
    if (uwRet != LOS_OK)
    {
        dprintf("内存池初始化失败!\n");
        return;
    }
    else {
        dprintf("内存池初始化成功!\n");
    }
    /*申请内存块*/
    p_num = (int*)LOS_MemboxAlloc(pBoxMem);
    if (NULL == p_num) {
        dprintf("内存分配失败!\n");
        return;
    }
    dprintf("内存分配成功\n");
    /*赋值*/
    *p_num = 828;
    dprintf("*p_num = %d\n", *p_num);
    /*清除内存内容*/
    LOS_MemboxClr(pBoxMem, p_num);
    dprintf("清除内存内容成功\n *p_num = %d\n", *p_num);
    /*释放内存*/
    uwRet = LOS_MemboxFree(pBoxMem, p_num);
    if (LOS_OK == uwRet) {
        dprintf("内存释放成功!\n");
    }
    else{
        dprintf("内存释放失败!\n");
    }
    return;

3.4 结果验证

图 3-6 结果显示

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

推荐阅读

  • 「网安夜校」开课啦!多门网络安全课程开启限时优惠报名

    众志成城,共抗疫情。腾讯安全联合腾讯云大学、腾讯课堂启动「网安夜校」,为大家提供限时优惠的网络安全课程。欢迎网络安全从业者和信息安全专业学生报名参加学习,快速充电提升自我。

    腾讯安全
    安全培训腾讯云大学
  • Flink源码走读(一):Flink工程目录

    导语 | Flink已经成为未来流计算趋势,目前在很多大厂已经有了大规模的使用。最近在学习Flink源码,就想把自己学习的过程分享出来,希望能帮助到志同道合的朋友。开始阅读源码,说明读者已经对flink的基本概念有一些了解,这里就不再重复介绍Flink了。本文作为学习过程的第一章,首先对Flink的工程目录做一个解读,了解了工程下各个模块的作用,才能在遇到问题时准确定位到代码,进一步学习。

    2011aad
    大数据解决方案
  • Flink源码走读(二):Flink+Kafka实现端到端Exactly Once语义

    Flink通过Checkpoint机制实现了消息对状态影响的Exactly Once语义,即每条消息只会影响Flink内部状态有且只有一次。但无法保证输出到Sink中的数据不重复。以图一所示为例,Flink APP收到Source中的A消息,将其转化为B消息输出到Sink,APP在处理完A1后做了一次Checkpoint,假设APP在处理到A4时发生错误重启,APP将会重新从A2开始消费并处理数据,就会导致B2和B3重复输出到Sink中两次。

    2011aad
    大数据解决方案Kafka
  • kubernetes系列教程(十九)使用metric-server让HPA弹性伸缩愉快运行

    kubernetes监控指标大体可以分为两类:核心监控指标和自定义指标,核心监控指标是kubernetes内置稳定可靠监控指标,早期由heapster完成,现由metric-server实现;自定义指标用于实现核心指标的扩展,能够提供更丰富的指标支持,如应用状态指标,自定义指标需要通过Aggregator和k8s api集成,当前主流通过promethues实现。

    HappyLau谈云计算
    Kubernetes容器微服务微服务架构腾讯微服务平台 TFS
  • 三分钟入坑指北 🔜 Docsify + Serverless Framework 快速创建个人博客系统

    之前由于学摄影的关系,为了提高自己的审美,顺便锻炼下自己的英文能力,翻译了不少国外艺术类的 文章。最近一直想搭一个个人博客来存放这些内容,又懒得折腾建站,遂一直搁置。

    Aceyclee
    ServerlessHTML网站GitGitHub
  • NVM作为主存上对数据库管理系统的影响

    implications of non-volatile memory as primary storage for database management systems

    yzsDBA
    存储缓存数据库数据结构SQL
  • DevOps平台架构演进

    附最新架构图https://www.processon.com/view/5cbd897de4b0bab90962c435

    我思故我在
    DevOps 解决方案微服务架构架构设计
  • 【腾讯云AI小程序大赛】中山大学作品《小耳朵天使》

    ----------------------------------------------------------------------------------

    陈华山
    小程序 · 云开发小程序语音识别文字识别对话机器人
  • Kona JDK 在腾讯大数据领域内的实践与发展

    经常听人谈到 OpenJDK,那它到底是什么呢?相信大家都听说过 Java SE、ME、EE等规范, 通常意义上对 Open JDK 的定义指:Java SE规范的一个免费和开源参考实现。

    腾小云
    JDKJavaJVM大数据Oracle
  • 公告丨腾讯安全产品更名通知

    为了更好地为政企客户的安全保驾护航,腾讯安全即日起更新旗下身份安全、网络安全、终端安全、应用安全、数据安全、业务安全、安全管理、安全服务等八类安全产品的命名,致力于打造全栈安全产品“货架”,让客户选购安全产品/服务更加便捷,更快地找到合适的安全产品,从而对自身的安全建设“对症下药”。

    腾讯安全
    DDoS 防护应用安全 MS验证码(业务安全)应用安全(移动安全)漏洞扫描服务

扫码关注云+社区

领取腾讯云代金券