---
title: 内存池部分介绍
description: "在Ascend Transformer Boost加速库（以下简称ATB）的调用流程中，往往需要频繁调用Malloc和Free向设备申请和释放内存空间，这样的操作会打断设备的流水，造成额外的性能开销。"
url: https://www.hiascend.com/document/detail/zh/canncommercial/latest/API/ascendtb/ascendtb_0054.html
sourcePath: /source/zh/canncommercial/900/API/ascendtb/ascendtb_0054.html
indexId: b8b4eee58b308fd1c04fb717806cc058e1032927508638eedd808bc3359e138f61
---
# 内存池部分介绍

在Ascend Transformer Boost加速库（以下简称ATB）的调用流程中，往往需要频繁调用Malloc和Free向设备申请和释放内存空间，这样的操作会打断设备的流水，造成额外的性能开销。

#### 内存池

内存池是一种常见的技术手段用于管理和分配设备的内存。其基本功能原理如下：

- 内存池预先申请一大块连续的内存空间，并将其分割为多种粒度的小块。
- 需要申请内存时，从空闲块中找到合适的块直接分配。
- 如果找不到合适的块，进行内存回收、申请扩展空间等操作获得合适的块。
- 内存释放时，将使用块标记为空闲，回收至内存池。


#### 主要结构

- MemoryBlock：
  一个Block至少需要三个元素，用于定位的索引、块大小描述和对应的实际物理地址。

```
struct MemoryBlock {
// blockId，内存块索引，全局唯一
int64_t blockId;
// blockSize，单位为字节
size_t blockSize;
// 内存块的物理地址
void *address = nullptr;
};
```


- MemoryPool：
  最基本的内存池，分别管理每个设备上的内存，一般其创建个数与设备数量对应。通常使用unordered_map的数据结构管理所有的block。它包含三个类方法，AllocateBlock、FreeBlock和GetBlockPtr，用于分配block、释放block和获取block中的内存地址。

- MemoryManager：
  内存管理类，负责初始化所有设备的MemoryPool，并将其放入一个数组中统一维护。当不同线程或进程访问该类并调用方法时，通过GetDeviceId方法获得线程对应的设备ID，并返回对应设备内存池的相应方法。


#### 关键函数

- MemoryPool::AllocateBlock
分配内存块方法，主要逻辑分为两个步骤：

  1. 在空闲块中查找是否有符合要求大小的内存块，找到了则将内存块索引返回，并将此内存块标记为已使用。
  2. 如果没有符合要求的内存块，但预申请内存还有剩余空间。先将剩余内存空间的首地址进行64字节对齐，在此基础上将申请分配大小向上对齐成32整数倍+32字节，构建内存块标记为已使用并返回索引。
- MemoryPool::FreeBlock
  释放内存块时，不直接释放内存，只是将其标记为未使用。


#### 使用内存池管理workspace内存

实现内存池的首要目的是减少aclrtMalloc和aclrtFree的调用次数，在本例中主要针对workspace的内存进行管理。

在Node类中会保存有当前已分配的workspace大小和对应的blockId。当需求的workspace大小发生变化时，如果需求大小小于当前已有空间则不进行操作，大于则释放当前内存块并重新申请更大的内存块。
