适用于 C++ 的 AWS SDK 中的内存管理 - 适用于 C++ 的 AWS SDK

适用于 C++ 的 AWS SDK 中的内存管理

适用于 C++ 的 AWS SDK 提供了一种控制库中的内存分配和取消分配的方法。

注意

仅当您使用通过已定义的编译时常量 USE_AWS_MEMORY_MANAGEMENT 构建的库版本时,自定义内存管理功能才可用。

如果您使用的库版本是在没有这个编译时常量的情况下构建的,那么像 InitializeAWSMemorySystem 这样的全局内存系统函数将不会生效;而是会使用全局 newdelete 函数。

有关编译时常量的更多信息,请参阅 STL 与 AWS 字符串和向量

分配和取消分配内存

分配或取消分配内存

  1. 子类 MemorySystemInterfaceaws/core/utils/memory/MemorySystemInterface.h

    class MyMemoryManager : public Aws::Utils::Memory::MemorySystemInterface { public: // ... virtual void* AllocateMemory( std::size_t blockSize, std::size_t alignment, const char *allocationTag = nullptr) override; virtual void FreeMemory(void* memoryPtr) override; };
    注意

    您可以根据需要更改 AllocateMemory 的类型签名。

  2. 使用 Aws::SDKOptions 结构来配置自定义内存管理器的用法。将该结构的实例传递到 Aws::InitAPI。在应用程序终止之前,必须对同一个实例调用 Aws::ShutdownAPI 来关闭 SDK。

    int main(void) { MyMemoryManager sdkMemoryManager; SDKOptions options; options.memoryManagementOptions.memoryManager = &sdkMemoryManager; Aws::InitAPI(options); // ... do stuff Aws::ShutdownAPI(options); return 0; }

STL 与 AWS 字符串和向量

使用内存管理器进行初始化时,适用于 C++ 的 AWS SDK 会将所有的内存分配和释放操作委托给该内存管理器。如果内存管理器不存在,SDK 将使用全局新建和删除。

如果您使用自定义 STL 分配器,则必须更改所有 STL 对象的类型签名以匹配分配策略。由于 SDK 的实现和接口中大量使用 STL,若 SDK 采用单一实现方式,将无法直接将默认 STL 对象传入 SDK,也无法对 STL 内存分配进行控制。另一种方案是混合实现方式 — 在内部使用自定义分配器,同时允许接口使用标准 STL 对象和自定义 STL 对象,但这种方式可能会增加内存问题的排查难度。

解决方案是使用内存系统的编译时常量 USE_AWS_MEMORY_MANAGEMENT 来控制 SDK 使用哪些 STL 类型。

如果启用编译时常量(设为开启状态),则相关类型会解析为 STL 类型,且这些 STL 类型会关联一个与 AWS 内存系统绑定的自定义分配器。

如果禁用编译时常量(设为关闭状态),则所有 Aws::* 类型都解析为相应的默认 std::* 类型。

来自 SDK 中 AWSAllocator.h 文件的示例代码

#ifdef USE_AWS_MEMORY_MANAGEMENT template< typename T > class AwsAllocator : public std::allocator< T > { ... definition of allocator that uses AWS memory system }; #else template< typename T > using Allocator = std::allocator<T>; #endif

在示例代码中,AwsAllocator 可以是自定义分配器或默认分配器,具体取决于编译时常量。

来自 SDK 中 AWSVector.h 文件的示例代码

template<typename T> using Vector = std::vector<T, Aws::Allocator<T>>;

在示例代码中,我们定义 Aws::* 类型。

如果启用编译时常量(设为开启状态),则该类型将映射到使用自定义内存分配和 AWS 内存系统的向量。

如果禁用编译时常量(设为关闭状态),则该类型将映射到带有默认类型参数的常规 std::vector

类型别名用于 SDK 中执行内存分配的所有 std:: 类型,例如容器、字符串流和字符串缓冲区。适用于 C++ 的 AWS SDK 使用这些类型。

其余问题

您可以控制该 SDK 中的内存分配;然而,STL 类型仍然在公共接口中占主导地位 — 通过模型对象的 initializeset 方法中的字符串参数实现。如果您不使用 STL 而是使用字符串和容器,那么每当您想进行服务调用时,都必须创建很多临时变量。

为了删除使用非 STL 进行服务调用时的大部分临时变量和内存分配,我们实现了以下内容:

  • 每个接收字符串的 Init/Set 函数都有一个接收 const char* 的重载。

  • 每个接收容器(地图/向量)的 Init/Set 函数都有一个接收单个条目的添加(add)变体。

  • 每个接收二进制数据的 Init/Set 函数都有一个重载,该重载接收指向数据的指针和 length 值。

  • (可选)每个接收字符串的 Init/Set 函数都有一个重载,该重载接收非零结尾的 const char* 和一个 length 值。

原生 SDK 开发工具和内存控件

在 SDK 代码中遵循以下规则:

  • 不要使用 newdelete;而是使用 Aws::New<>Aws::Delete<>

  • 不要使用 new[]delete[];而是使用 Aws::NewArray<>Aws::DeleteArray<>

  • 不要使用 std::make_shared;而是使用 Aws::MakeShared

  • 使用 Aws::UniquePtr 表示指向单个对象的唯一指针。使用 Aws::MakeUnique 函数创建唯一指针。

  • 使用 Aws::UniqueArray 表示指向对象数组的唯一指针。使用 Aws::MakeUniqueArray 函数创建唯一指针。

  • 不要直接使用 STL 容器;使用其中一个 Aws:: typedef 或者为所需的容器添加一个 typedef。例如:

    Aws::Map<Aws::String, Aws::String> m_kvPairs;
  • 使用 shared_ptr 表示传入 SDK 并由 SDK 管理的任何外部指针。必须使用与对象分配方式相匹配的销毁策略来初始化共享指针。如果 SDK 不应该清理指针,则您可以使用原始指针。