内存管理

内存管理的目标

建立合理的机制,将内存快速、高效(使用率)及安全的分配给需要的申请者。

内存申请行为的分类

对于内存申请行为有如下几种可能:

  • 编译时确定
    如果程序在设计时就能确定某种数据结构需要实例化的数量,应该优先使用全局变量。这样可以利用编译器来进行内存空间检查。

    如一辆脉轮小车底盘的电机速度环 PID 。

  • 运行时确定
    某种数据结构在编译时无法确定所有信息(如通信缓冲区大小或打开文件的数量)。这种情况下可以考虑使用堆内存

    • 长时间持有
      某些应用中,一旦申请内存,就几乎不会释放或是在可预见的时间段内都不会将其释放,这种情况称为长时间持有。
      应按具体情况选择全局变量或是堆内存申请。

    • 短时间持有
      对于某些事件,可以明确估计出该事件的处理器的响应时间,从而估算出某内存空间的使用时间,这种情况被称为短时间持有的内存申请。

      • 若该事件频率较低且所需内存空间较小,则可考虑使用池内存
      • 若频率较高或所需内存空间较大,则可考虑使用堆内存或全局变量。

内存管理的数据结构

内存堆

内存是一块连续的大容量内存空间。当用户申请内存时,将从内存堆上划分出一个完整的块分配给用户使用。这些被划分出的块是连续稠密的。

堆的用途

堆被设计出来尽可能高密度的分配空间。当多次申请/释放后,极易产生内存碎块。另外,在分配时会伴随着较复杂的分配查找算法,因此不适用于小内存、高申请密度的内存申请。

堆的结构

  • 堆的元数据

内存池

内存是一块包含多个预分配块的内存栈。当用户申请时,弹出一块内存给用户使用;释放时重新压栈。

池的用途

堆被设计出来用以快速分配内存块,且避免了内存的碎片化。

池的结构

在池内未使用的内存块在逻辑上以栈的方式呈现(但由双向链表实现),但在使用时会将全部内存空间分配给用户。这样做避免了因链表结构占用而产生的浪费。

注意:因为一整块内存(包括链表信息)都将分配给用户,所以用户释放时需要重新作为链表结点初始化后再压栈。

GC

当内存被释放时,内存块不会直接被回收,而是标记为垃圾块,等待空闲时间时再由内核进程回收。

内存在释放时会进行完整性检查。