AWS SDK for C++ でのメモリ管理 - AWS SDK for C++

AWS SDK for C++ でのメモリ管理

AWS SDK for C++ は、ライブラリ内でのメモリの割り当てと解放を制御する方法が提供します。

注記

カスタムメモリ管理を利用できるのは、コンパイル時定数 USE_AWS_MEMORY_MANAGEMENT を定義してビルドされたライブラリを使用する場合のみです。

コンパイル時定数なしでビルドされたバージョンのライブラリを使用した場合、InitializeAWSMemorySystem などのグローバルなメモリシステム関数は機能せず、代わりにグローバルな new および delete 関数が使用されます。

このコンパイル時定数の詳細については、「STL および AWS 文字列とベクター」を参照してください。

メモリの割り当てと解放

メモリを割り当てまたは解放するには

  1. サブクラス 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 の型シグネチャを変更できます。

  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 文字列とベクター

メモリマネージャーで初期化されると、AWS SDK for C++ はすべての割り当てと解放をメモリマネージャーに委譲します。メモリマネージャーが存在しない場合、SDK はグローバルな new と delete を使用します。

カスタム STL アロケーターを使用する場合は、すべての STL オブジェクトの型シグネチャをアロケーションポリシーに合わせて変更する必要があります。SDK の実装とインターフェイスで STL が広く使用されているため、SDK で 1 つの方式を採用すると、デフォルトの STL オブジェクトの直接的な受け渡しや割り当て制御が難しくなります。あるいは、内部ではカスタムアロケーターを使用しつつ、インターフェイスでは標準およびカスタム STL オブジェクトの両方を許容するハイブリッド方式も考えられますが、この方式ではメモリ問題の調査が難しくなる可能性があります。

この問題への解決策は、メモリシステムのコンパイル時定数 USE_AWS_MEMORY_MANAGEMENT を用いて、SDK が使用する STL 型を制御することです。

このコンパイル時定数が有効 (on) になっている場合、各型は、AWS メモリシステムに接続されたカスタムアロケーターを使用する STL 型に解決されます。

コンパイル時定数が無効 (off) の場合、すべての 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::* 型を定義しています。

コンパイル時定数が有効 (on) の場合、この型はカスタムメモリアロケーターと AWS メモリシステムを使用するベクターに解決されます。

コンパイル時定数が無効 (off) の場合、この型はデフォルトの型パラメータを持つ通常の std::vector に解決されます。

型エイリアスは、コンテナ、文字列ストリーム、文字列バッファなど、SDK 内でメモリ割り当てを行うすべての std:: 型に使用されます。AWS SDK for C++ はこれらの型を使用します。

残された課題

SDK 内のメモリ割り当ては制御できますが、STL 型は依然としてモデルオブジェクトの initialize および set メソッドの文字列パラメータを通じて、パブリックインターフェイスに多く使用されています。STL を使用せずに、代わりに文字列やコンテナを使用している場合、サービス呼び出しのたびに多くの一時オブジェクトを作成する必要があります。

STL を使用せずにサービス呼び出しを行う際の一時オブジェクトやメモリ割り当てを削減するために、次の対策を実装しています。

  • 文字列を受け取るすべての Init/Set 関数には、const char* を受け取るオーバーロードがあります。

  • コンテナ (マップ/ベクター) を受け取る Init/Set 関数には、1 つのエントリを受け取る 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 を使用します。

  • 1 つのオブジェクトへの一意のポインタには Aws::UniquePtr を使用します。一意のポインタを生成するには、Aws::MakeUnique 関数を使用します。

  • オブジェクトの配列への一意のポインタには、Aws::UniqueArray を使用します。一意のポインタを生成するには、Aws::MakeUniqueArray 関数を使用します。

  • STL コンテナを直接使用しないでください。Aws:: typedef のいずれかを利用するか、必要なコンテナに typedef を追加してください。例:

    Aws::Map<Aws::String, Aws::String> m_kvPairs;
  • SDK に渡して管理される外部ポインタには shared_ptr を使用します。共有ポインタは、オブジェクトの生成方法に合った破棄ポリシーで初期化する必要があります。SDK がポインタのクリーンアップを行わない場合は、生ポインタを使用できます。