6.2 静态内存分配模式

Bruce Powel Douglass大师介绍-CSDN博客icon-default.png?t=N7T8https://blog.csdn.net/ChatCoding/article/details/134665868

嵌入式软件开发从小工到专家-CSDN博客icon-default.png?t=N7T8https://blog.csdn.net/ChatCoding/article/details/135297955

C嵌入式编程设计模式源码-CSDN博客icon-default.png?t=N7T8https://blog.csdn.net/ChatCoding/article/details/134819019

静态分配模式只适用于负载(内存量)高度可预测且稳定的简单系统。在适用的情况下,使用这种模式可以使系统易于设计和维护。

6.2.1 摘要

动态内存分配在实时嵌入式系统中存在两个主要问题:

  • 内存分配和释放的时间不确定。
  • 内存碎片化。

这种模式采用了一种非常简单的方法来解决这两个问题:禁止动态内存分配。这意味着所有对象都在系统初始化期间分配。如果设计时能够知道内存负载,并且能够为最坏情况分配足够的内存,那么系统虽然初始化时间会长一点,但运行时将更加稳定高效。

6.2.2 问题

动态内存分配在结构化和面向对象设计中非常普遍。例如,C++ 语言使用 newdelete 来分配和释放内存,C 语言则使用 mallocfree。在这些语言中,程序员都需要显式执行这些操作,但也很难想象任何大型程序不使用分配内存的指针。而 Java 语言更加彻底,所有对象都存放在动态内存中,这意味着所有对象创建都隐式地使用了动态内存分配。此外,Java 还会在内存不再使用时自动释放它,但具体何时何地发生则不在程序员的控制范围内。

尽管很常见,动态内存分配始终是让实时系统开发疼痛的问题,主要有以下三个难题:

  • 非确定性:动态内存分配和释放的时机通常是不可预测的,因为这通常需要搜索数据结构以找到可分配的空闲内存。这会导致系统的行为难以预测,甚至出现不可预料的延迟或中断。
  • 内存泄漏:如果程序员没有正确释放不再使用的内存,就会发生内存泄漏。这会导致系统内存的逐渐减少,最终导致系统崩溃。
  • 内存碎片化:由于内存是以不同大小的块分配的,释放顺序通常与分配顺序无关。这会导致空闲内存出现碎片化,即无法找到足够大的连续空闲内存块来满足新的内存请求。

上述三个难题都可能导致实时系统出现严重的性能问题或甚至崩溃。因此,在实时系统中,应尽量避免使用动态内存分配。

6.2.3 模式结构

图 6-1 展示了该模式的基本结构。它结构非常简单,但可以通过嵌套抽象层来处理任意大小的系统。系统对象启动初始化过程,并创建最高级别的复合对象。这些复合对象通过组合关系连接到其他复合对象或原始对象。原始对象被定义为不会动态创建其他对象的类。使用组合关系是因为它们清晰地标识了创建/删除的责任。

6.2.4 协作角色

  • Allocation Plan(分配计划):如果存在,标识最大系统复合对象应该按照哪个顺序分配。
  • Composite Object(复合对象):复合对象通过组合关系负责创建它所拥有的所有对象。

分配计划

分配计划(Allocation Plan)是可选的,用于指定最大系统复合对象的分配顺序。如果没有分配计划,则系统可以按任何所需的顺序分配对象。

复合对象

复合对象(Composite Object)是指与其他对象之间存在组合关系的对象,其他对象可以是复合对象或原始对象。复合对象负责通过组合创建它所拥有的所有对象。复合对象和系统对象都不能释放内存。

复合对象可以由其他复合对象组成,但每个通过组合关系拥有的对象只能属于一个复合对象。这意味着模式中清楚地标识了系统中每个对象的创建责任。

部件对象

部件对象(Part Object)是复合对象和原始对象的父类。它允许系统对象和复合对象通过组合包含复合对象和原始对象。

原始对象

原始对象(Primitive Object)是指不负责分配任何其他对象的类。所有原始对象由复合对象创建。

系统对象

系统对象(System Object)是系统中最高抽象层级的对象。它的职责是通过创建和初始化系统的主要部分(最高级别的复合对象)来“启动”系统。这些复合对象又会创建自己的部分,依此类推。一旦所有对象都创建完毕,系统对象就会通过运行 begin 操作启动系统执行。

6.2.5 结果

静态分配模式将所有对象都在系统启动时进行内存分配,适用于以下情况:

  1. 最坏情况可预测且内存充裕: 系统的峰值内存需求是已知且可控的,并且拥有足够的内存满足这种情况。
  2. 内存负载稳定: 系统在不同运行状况下的内存需求差异不大,保持相对稳定的内存占用。
  3. 系统规模较小: 需要预先分配所有对象内存的特点限制了系统规模,适合用于较小的系统。
  4. 对内存成本不敏感: 系统对内存成本相对不敏感,预先分配内存造成的潜在浪费可以承受。

使用静态分配模式的系统拥有以下优势:

  • 更快的运行速度: 启动后执行代码无须进行动态内存分配,运行速度通常比动态分配更快,有时显著更快。
  • 更可预测的执行: 消除了动态分配带来的非确定性因素,使系统运行更加可预测。
  • 无内存碎片化: 不进行内存释放,就不会出现内存碎片化的问题。

然而,静态分配模式也存在一定的缺点:

  • 启动时间较长: 需分配所有对象内存,导致启动时间可能明显延长,对启动时间要求苛刻的系统可能不适用。
  • 潜在内存浪费: 预先分配所有对象内存可能造成一定程度的浪费,如果实际内存需求低于最坏情况,则会占用额外的内存空间。

总结: 静态分配模式适用于最坏情况可预测、内存负载稳定、规模较小且对内存成本不敏感的系统。它能带来更快的运行速度、更可预测的执行和无碎片化等优势,但需要付出启动时间较长和潜在内存浪费的代价。

6.2.6 实施策略

这个模式非常容易实现。在许多情况下,甚至不需要单独的初始化方法,可以直接使用每个复合对象的构造函数来完成对象的创建和初始化。

6.2.7 相关模式

本章中介绍的其他模式也解决了类似的问题,但会带来略有不同的利弊。例如,池分配模式、固定大小缓冲区模式、垃圾回收器模式和垃圾压缩器模式等等。

6.2.8 示例模型

图6-2展示了一个使用完全构建系统实例的简单例子。图6-2a展示了对象图的实例结构,图6-2b展示了静态分配模式在启动时的工作方式。

总结来说,静态分配模式通过在系统启动时分配所有对象,避免了动态内存分配带来的时间不确定性和内存碎片化问题。这种模式适用于内存负载可预测、系统设计简单且内存成本不是主要考虑因素的情况。在实施时,需要在设计阶段对内存需求有准确的预测,以确保在最坏情况下有足够的内存。

图形中各个箭头的含义

  • 实线箭头:代表对象之间的组合关系

图形中各个对象的含义

  • 起搏器对象(Pacemaker Object):这是整个起搏器设备的总称。
    • 电池系统(Battery Subsystem):为起搏器提供动力。
      • 电池传感器(Battery Sensor):监测电池的电压,并在电池电量不足时向起搏器发出警报。
    • 通信子系统(Comm Subsystem):允许起搏器与外部设备(如程序器和监控系统)进行通信。它使用无线遥测系统来传输和接收数据。
      • 磁簧开关(Reed Switch):检测起搏器是否置于磁场中。这可用于激活起搏器的某些功能,例如遥测。
      • 消息队列(Message Queue):用于存储由通信子系统传输或接收的数据。
      • 收发器线圈(Transceiver Coil):用于无线传输和接收数据。
    • 起搏子系统(Pacing Subsystem):起搏器的核心
      • 心房(Atrial Chamber):心脏的上腔。
        • A 心脏传感器(A Heart Sensor):监测心房的电活动。
        • A 起搏电容器(A Pacing Canacitor):为起搏电路存储能量。
      • 心室(Ventricular Chamber):心脏的下腔。
        • V 心脏传感器(V Heart Sensor):监测心室的电活动。
        • V 起搏电容器(V Pacing Capacitor):为起搏电路存储能量。

起搏子系统(Pacing Subsystem):起搏器的核心,负责生成电脉冲来刺激心肌。它由起搏电路、起搏电极和起搏电容器组成。

  • 起搏电路(Pacing Circuit):生成电脉冲。
  • 起搏电极(Pacing Electrode):将脉冲传递给心肌。
  • 起搏电容器(Pacing Capacitor):为起搏电路存储能量。

相关推荐

  1. 设计模式-单例模式静态内部类)

    2024-01-31 08:26:01       35 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-01-31 08:26:01       98 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-01-31 08:26:01       106 阅读
  3. 在Django里面运行非项目文件

    2024-01-31 08:26:01       87 阅读
  4. Python语言-面向对象

    2024-01-31 08:26:01       96 阅读

热门阅读

  1. 分布式集群如何保证线程安全

    2024-01-31 08:26:01       49 阅读
  2. 贪吃蛇游戏中显示贪吃蛇的路线和蛇的宽度

    2024-01-31 08:26:01       51 阅读
  3. Maltab 输出矢量图

    2024-01-31 08:26:01       57 阅读
  4. CSS transition(过渡效果)详解

    2024-01-31 08:26:01       53 阅读
  5. 如何发布自己的npm包

    2024-01-31 08:26:01       67 阅读
  6. 后端课程接口

    2024-01-31 08:26:01       53 阅读
  7. ARM与X86架构的区别与联系

    2024-01-31 08:26:01       55 阅读
  8. MySQL 函数参考手册(MySQL 高级函数)

    2024-01-31 08:26:01       38 阅读
  9. 基于paddlepaddle的yolo基本实现

    2024-01-31 08:26:01       46 阅读