Memory Management
The AWS SDK for C++ provides a way to control memory allocation and deallocation in a library.
Note
Custom memory management is available only if you use a version of the library built using
the defined compile-time constant AWS_CUSTOM_MEMORY_MANAGEMENT
.
If you use a version of the library that is built without the compile-time constant, global
memory system functions such as InitializeAWSMemorySystem
won’t work; the global new
and
delete
functions are used instead.
For more information about the compile-time constant, see STL and AWS Strings and Vectors.
Allocating and Deallocating Memory
To allocate or deallocate memory
-
Subclass
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; };
Note
You can change the type signature for
AllocateMemory
as needed. -
Install a memory manager with an instance of your subclass by calling
InitializeAWSMemorySystem
. This should occur at the beginning of your application. For example, in yourmain()
function:int main(void) { MyMemoryManager sdkMemoryManager; Aws::Utils::Memory::InitializeAWSMemorySystem(sdkMemoryManager); // ... do stuff Aws::Utils::Memory::ShutdownAWSMemorySystem(); return 0; }
-
Just before exit, call
ShutdownAWSMemorySystem
(as shown in the preceding example, but repeated here):Aws::Utils::Memory::ShutdownAWSMemorySystem();
STL and AWS Strings and Vectors
When initialized with a memory manager, the AWS SDK for C++ defers all allocation and deallocation to the memory manager. If a memory manager doesn’t exist, the SDK uses global new and delete.
If you use custom STL allocators, you must alter the type signatures for all STL objects to match the allocation policy. Because STL is used prominently in the SDK implementation and interface, a single approach in the SDK would inhibit direct passing of default STL objects into the SDK or control of STL allocation. Alternately, a hybrid approach—using custom allocators internally and allowing standard and custom STL objects on the interface—could potentially make it more difficult to investigate memory issues.
The solution is to use the memory system’s compile-time constant AWS_CUSTOM_MEMORY_MANAGEMENT
to
control which STL types the SDK uses.
If the compile-time constant is enabled (on), the types resolve to STL types with a custom allocator connected to the AWS memory system.
If the compile-time constant is disabled (off), all Aws::*
types resolve to the corresponding
default std::*
type.
Example code from the ``AWSAllocator.h`` file in the SDK
#ifdef AWS_CUSTOM_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
In the example code, the AwsAllocator
can be a custom allocator or a default allocator,
depending on the compile-time constant.
Example code from the ``AWSVector.h`` file in the SDK
template<typename T> using Vector = std::vector<T, Aws::Allocator<T>>;
In the example code, we define the Aws::*
types.
If the compile-time constant is enabled (on), the type maps to a vector using custom memory allocation and the AWS memory system.
If the compile-time constant is disabled (off), the type maps to a regular std::vector
with
default type parameters.
Type aliasing is used for all std::
types in the SDK that perform memory allocation, such as
containers, string streams, and string buffers. The AWS SDK for C++ uses these types.
Remaining Issues
You can control memory allocation in the SDK; however, STL types still dominate the public interface
through string parameters to the model object initialize
and set
methods. If you don’t use
STL and use strings and containers instead, you have to create a lot of temporaries whenever you
want to make a service call.
To remove most of the temporaries and allocation when you make service calls using non-STL, we have implemented the following:
-
Every Init/Set function that takes a string has an overload that takes a
const char*
. -
Every Init/Set function that takes a container (map/vector) has an add variant that takes a single entry.
-
Every Init/Set function that takes binary data has an overload that takes a pointer to the data and a
length
value. -
(Optional) Every Init/Set function that takes a string has an overload that takes a non-zero terminated
const char*
and alength
value.
Native SDK Developers and Memory Controls
Follow these rules in the SDK code:
-
Don’t use
new
anddelete
; useAws::New<>
andAws::Delete<>
instead. -
Don’t use
new[]
anddelete[]
; useAws::NewArray<>
andAws::DeleteArray<>
. -
Don’t use
std::make_shared
; useAws::MakeShared
. -
Use
Aws::UniquePtr
for unique pointers to a single object. Use theAws::MakeUnique
function to create the unique pointer. -
Use
Aws::UniqueArray
for unique pointers to an array of objects. Use theAws::MakeUniqueArray
function to create the unique pointer. -
Don’t directly use STL containers; use one of the
Aws::
typedefs or add a typedef for the container you want. For example:Aws::Map<Aws::String, Aws::String> m_kvPairs;
-
Use
shared_ptr
for any external pointer passed into and managed by the SDK. You must initialize the shared pointer with a destruction policy that matches how the object was allocated. You can use a raw pointer if the SDK is not expected to clean up the pointer.