适用于 C++ 的 AWS SDK 中的内存管理
适用于 C++ 的 AWS SDK 提供了一种控制库中的内存分配和取消分配的方法。
注意
仅当您使用通过已定义的编译时常量 USE_AWS_MEMORY_MANAGEMENT 构建的库版本时,自定义内存管理功能才可用。
如果您使用的库版本是在没有这个编译时常量的情况下构建的,那么像 InitializeAWSMemorySystem 这样的全局内存系统函数将不会生效;而是会使用全局 new 和 delete 函数。
有关编译时常量的更多信息,请参阅 STL 与 AWS 字符串和向量。
分配和取消分配内存
分配或取消分配内存
-
子类
MemorySystemInterface:aws/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的类型签名。 -
使用
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 类型仍然在公共接口中占主导地位 — 通过模型对象的 initialize 和 set 方法中的字符串参数实现。如果您不使用 STL 而是使用字符串和容器,那么每当您想进行服务调用时,都必须创建很多临时变量。
为了删除使用非 STL 进行服务调用时的大部分临时变量和内存分配,我们实现了以下内容:
-
每个接收字符串的 Init/Set 函数都有一个接收
const char*的重载。 -
每个接收容器(地图/向量)的 Init/Set 函数都有一个接收单个条目的添加(add)变体。
-
每个接收二进制数据的 Init/Set 函数都有一个重载,该重载接收指向数据的指针和
length值。 -
(可选)每个接收字符串的 Init/Set 函数都有一个重载,该重载接收非零结尾的
const char*和一个length值。
原生 SDK 开发工具和内存控件
在 SDK 代码中遵循以下规则:
-
不要使用
new和delete;而是使用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 不应该清理指针,则您可以使用原始指针。