Photon C++ Client API  4.1.15.3
Classes | Functions
ExitGames::Common::MemoryManagement Namespace Reference

Classes

class  AllocatorInterface
 

Functions

 __attribute__ ((weak)) AllocatorInterface *AllocatorInterface
 

HighLevelMemoryManagement

The template functions in this section are an alternative for the C++ dynamic memory management operators new, new[], delete and delete[].

They are implemented in terms of enhancing the Low Level Memory Management macros and for this reason offer similar advantages over new and co like those macros offer over malloc and co.

However same as new and co they also construct and destruct the objects that they allocate and deallocate.

void setMaxAllocSize (size_t maxAllocSize)
 
void setMaxSizeForAllocatorUsage (size_t maxSizeForAllocatorUsage)
 
void setAllocator (ExitGames::Common::MemoryManagement::AllocatorInterface &allocator)
 
void setAllocatorToDefault (void)
 
template<typename Ftype >
Ftype * allocate (void)
 
template<typename Ftype >
Ftype * allocateArray (size_t count)
 
template<typename Ftype >
Ftype * reallocateArray (Ftype *p, size_t count)
 
template<typename Ftype >
void deallocate (const Ftype *p)
 
template<typename Ftype >
void deallocateArray (const Ftype *p)
 

Detailed Description

MemoryManagement

Function Documentation

§ setMaxAllocSize()

void ExitGames::Common::MemoryManagement::setMaxAllocSize ( size_t  maxAllocSize)

Sets the max size of memory that might get allocated ahead of time as a result of a single memory request.

Requesting memory from the OS is an expensive operation. This is why a good memory manager might choose to request bigger amounts of memory at once and give out smaller chunks of them to the application code. This way it can reduce the amount of necessary memory requests to the OS. Depending on the memory requests that come in from the application code, a memory manager might decide to scale up its own requests to the OS.

You can set an upper limit for how much the currently active memory manager is allowed to scale up through this function.

Example: Consider a pool-based memory manager that uses multiple memory pools, where each serves requests for memory of different sizes. There could be a pool for tiny memory requests, one for small requests, one for medium requests, and so on.

Now let's imagine that there is a pool that serves requests between 65 and 128 bytes in size each and for this purpose keeps a bunch of 128 byte blocks around to give out to requesters. In the beginning it might just keep very few such blocks around, as the memory manager does not know, how many blocks of this size an app might need to use in parallel. When an app requests lots of those blocks, the pool would scale accordingly and to not need to do a request to the OS too often, it might increase the size of it's own requests. i.e. at first it could have just 4 blocks around, then when it resizes, it would allocate memory for another 4 blocks, then for 8 more, then for another, 16, then 32, 64, 128, 256, 512, 1024 blocks more, and so on.

Now if you set an upper limit of 8192 bytes, then the pool would not increase the size of its requests to the OS beyond that limit. For that 128 byte blocks pool that would mean that it would request at max 8192/128==64 blocks at once. So the resize pattern from above would change to 4, 8, 16, 32, 64, 64, 64, 64, and so on.

Accordingly with the same 8192 bytes limit in place a pool that holds 1024 byte blocks would not allocate memory for more than 8 such blocks at once.

Note
This does not set a limit to the overall memory that might get allocated, but only to the memory that gets allocated as a direct result of a single memory request. The very next request might already lead to another allocation if the memory manager decides so (for example a pool based memory manager might serve differently sized requests from different pools that resize independently from each other).
Remarks
This function forwards the passed in value to the currently set allocator (see setAllocator() ) and does not store it itself. For this reason a call to this function only affects the settings of the currently set allocator and not those of any future allocator, that might be set by setAllocator() at any point in time after this function got called.
It is the responsibility of the allocator to honor the the setting that the user has applied through this function.
Parameters
maxAllocSizethe max size for a single memory request to the OS
See also
setAllocator(), AllocatorInterface

§ setMaxSizeForAllocatorUsage()

void ExitGames::Common::MemoryManagement::setMaxSizeForAllocatorUsage ( size_t  maxSizeForAllocatorUsage)

Sets a limit up to which memory requests get forwarded to the set allocator. Requests with a size above the limit get redirected to the OS instead.

Requesting memory from the OS is an expensive operation.

For frequent requests of small amounts of memory it is usually more efficient to request that memory from a memory manager instead, which requests bigger amounts of memory from the OS at once, splits them up into smaller blocks and returns those smaller blocks to the requester.

However this is effectively a trade of reduced execution time bought with increased memory usage, which is usually a good deal for frequent small requests, but a bad deal for infrequent requests of bigger amounts of memory.

For this reason from a certain request size on requests get forwarded directly to the OS instead of to the set allocator.

This function lets you set the upper limit up to which the set allocator is used.

Requests above the limit will be forwarded directly to the OS.

Remarks
The value that is set through this function affects all allocators, not just the currently set one.
Parameters
maxSizeForAllocatorUsagethe max size for a memory request up to which the set allocator gets used
See also
setAllocator(), AllocatorInterface

§ setAllocator()

void ExitGames::Common::MemoryManagement::setAllocator ( ExitGames::Common::MemoryManagement::AllocatorInterface allocator)

Sets the allocator that will be used by future memory requests to the provided value.

All dynamic memory allocation requests by the Photon Client libraries go either through one of functions in MemoryManagement or through one of the Low Level Memory Management macros. The application code can also use these functions and macros for its own memory requests if its developer chooses so.

Each request for an amount of memory that does not exceed the limit set by setMaxSizeForAllocatorUsage() gets forwarded to an allocator. Photon provides a default general-purpose allocator that uses pool based memory management and that works well for most applications.

However you can set your own allocator through this function and Photon will use that allocator for any memory requests that happen afterwards.

Regarding potential reasons for writing your own custom allocator please see https://en.wikipedia.org/wiki/Allocator_(C%2B%2B)#Custom_allocators.

Remarks
Photons memory management stores the address of the allocator that served a specific memory request and forwards a request to free memory to the same allocator that allocated that memory.
This means a) that you can set a different allocator as often as you like at any point in time you like and b) that you need to keep any once set allocator available even when it is no longer set as the currently used allocator, at least until you can guarantee that all memory that once got requested from it, got returned to it and non of it is still in use.
If you want to already set an initial custom allocator before any global or file-level static instances of Photon classes get constructed, then you need to replace AllocatorInterface::get().
Parameters
allocatoran instance of a subclass of AllocatorInterface
See also
setMaxSizeForAllocatorUsage(), AllocatorInterface, AllocatorInterface::get()

§ setAllocatorToDefault()

void ExitGames::Common::MemoryManagement::setAllocatorToDefault ( void  )

Calls setAllocator() with Photons default allocator as parameter.

See also
setAllocator()

§ allocate()

Ftype* ExitGames::Common::MemoryManagement::allocate ( void  )

This function allocates a new instance of the type, that has been specified as first template parameter, on dynamic memory and properly initializes it. For an instance of a class type this includes calling a constructor on the instance.

Instances, that have been allocated with allocate(), have to be deallocated with deallocate(), when they are no longer needed.

Up to 10 optional arguments can be passed to allocate() and allocate() will call a constructor with the matching number of parameters and matching parameter types. If the class of the object that is to be constructed, doesn't provide a constructor with a matching signature, if that constructor isn't publicly accessible or if it is ambiguous, which constructor to choose, then the call to allocate() will trigger an error from the compiler..

The allocation is implemented via a call to EG_MALLOC().

§ allocateArray()

Ftype* ExitGames::Common::MemoryManagement::allocateArray ( size_t  count)

This function allocates an array of new instances of the type, that has been specified as first template parameter, on dynamic memory and properly initializes all of them. For arrays of class types this includes constructing each element via a constructor with matching parameter list.

Instances, that have been allocated with allocateArray(), have to be deallocated with deallocateArray(), when they are no longer needed.

The passed element count is allowed to be 0. In that case this function still allocates storage to store the element count of 0 in, so the returned address still has to be deallocated later.

Up to 10 optional arguments can be passed to allocateArray() and allocateArray() will call a constructor with the matching number of parameters and matching parameter types. If the class of the elements that are to be constructed, doesn't provide a constructor with a matching signature, if that constructor isn't publicly accessible or if it is ambiguous, which constructor to choose, then the call to allocateArray() will trigger an error from the compiler.

The allocation is implemented via a call to EG_MALLOC().

Parameters
countthe amount of elements that the new array should have

§ reallocateArray()

Ftype* ExitGames::Common::MemoryManagement::reallocateArray ( Ftype *  p,
size_t  count 
)

This function resizes an array, that has previously been allocated with allocateArray().

The function allocates a new array of the same type as the provided one, but with the requested element count. Afterwards it copies all elements of the old array that fit into the new array into the new array by calling the copy constructor of the class of the elements.

If the new element count is lower than the old one, then the corresponding elements at the end of the old array don't get copied over to the new one, but are just destructed.

If the new requested element count is higher than the old one, then the remaining uninitialized elements in the new array get constructed by choosing the constructor that matches the provided optional arguments to reallocateArray() best (no optional arguments means the default constructor gets called).

Finally the old array gets deallocated via deallocateArray() and the new array gets returned.

The returned address will most likely not match the passed one.

The passed address is allowed to be NULL. In that case this function behaves likes allocateArray().

The passed element count is allowed to be 0. In that case this function still allocates storage to store the element count of 0 in, so the returned address still has to be deallocated later.

If the passed address has not previously been returned by a call to allocateArray() or reallocateArray() and also isn't NULL or if it has already been passed to deallocateArray(), then the behavior is undefined.

Up to 10 optional arguments can be passed to reallocateArray() and reallocateArray() will call a constructor with the matching number of parameters and matching parameter types on each element of the new array, which hasn't already been copy-constructed from the corresponding element in the old array. If the class of the elements that are to be constructed, doesn't provide a constructor with a matching signature or if it doesn't provide a copy constructor, if that constructor or copy constructor isn't publicly accessible or if it is ambiguous, which constructor to choose, then the call to reallocateArray() will trigger an error from the compiler.

Parameters
pthe address of the array, that is to be resized
countthe new amount of elements that the array should have

§ deallocate()

void ExitGames::Common::MemoryManagement::deallocate ( const Ftype *  p)

Call this function to destruct and deallocate an instance, that has previously been allocated and constructed by a call to allocate().

The passed address is allowed to be NULL. In that case the call doesn't have any effect.

If the passed adress has not previously been returned by a call to allocate() and also isn't NULL, then the behavior is undefined.

Parameters
pthe address of the instance, that should be deallocated

§ deallocateArray()

void ExitGames::Common::MemoryManagement::deallocateArray ( const Ftype *  p)

Call this function to destruct and deallocate an array, that has previously been allocated and constructed by a call to allocateArray().

This function will call their destructor on all elements of the array and then deallocate the memory of the array.

The passed address is allowed to be NULL. In that case the call doesn't have any effect.

If the passed adress has not previously been returned by a call to allocateArray() or reallocateArray() and also isn't NULL, then the behavior is undefined.

Parameters
pthe address of the array, that should be deallocated.