ATLAS Offline Software
|
Collection of memory allocators with a common lifetime, plus subsystem summary. More...
#include "AthAllocators/ArenaBase.h"
#include "AthAllocators/ArenaHeader.h"
#include "AthAllocators/ArenaAllocatorCreator.h"
#include "AthAllocators/ArenaAllocatorBase.h"
#include <cstdlib>
#include <string>
#include <ostream>
Go to the source code of this file.
Classes | |
class | SG::Arena |
Collection of memory allocators with a common lifetime,. More... | |
class | SG::Arena::Push |
Helper class for making Arena instances current in a stack-like manner. More... | |
Namespaces | |
SG | |
Forward declaration. | |
Collection of memory allocators with a common lifetime, plus subsystem summary.
First, a bit of terminology; this also summarizes the major components of the library. This will be followed by more detailed descriptions. See also the individual class headers.
A Handle is the interface the application uses to allocate memory. A Handle is templated on the type being allocated as well as on the underlying Allocator. When a Handle is constructed, it is associated with the Allocator associated with the Arena that is current at that time (a new Allocator is automatically created if required). Therefore, a Handle should not be passed between threads, and Handle objects should not exist across any point where the current store/Arena may be changed.
A Handle also holds a lock on its associated allocator. Therefore, if you try to create two handle instances referencing the same allocator (i.e, same type and same thread), you'll get a deadlock.
Multiple Handle implementations may be available, implementing different strategies for initializing the elements.
Here are some more details about these components. For full details, see the individual class headers.
An Allocator is the fundamental allocator for a single type. Allocator instances generally request memory from the system in big blocks and then divide it up into individual elements. The memory allocated from the system is generally not returned to the system unless explicitly requested; elements not currently in use are kept in a pool for fast allocation. An Allocator class does not depend on the type being allocated. Instead, the necessary information is passed to the Allocator on creation in a parameters structure. This includes the element size, as well as three function pointers:
Any of these may be null, in which case the corresponding call is skipped.
An Allocator has a name, which is used both to identify it in the Allocator registry when Allocators are created on demand and in memory statistics reports. An Allocator must support these operations:
allocate
, to allocate a new element.reset
, to free all allocated elements. The memory will generally be retained by the Allocator to be reused again quickly.erase
, to free all allocated elements, and return all allocated memory to the system.reserve
, to adjust the amount of current unused memory which the Allocator keeps in its pool. If the amount of memory requested is greater than what is currently available, the new memory will usually be allocated in a single block. If the amount of memory requested is less than what is currently available, free blocks will be returned to the system, if possible.name
to return the Allocator's name, and stats
to return the current statistics for the Allocator.There are some additional operations which an Allocator may optionally implement:
free
, to free an individual element.resetTo
, to free all elements that were allocated after a given element, as well as the element itself.Two Allocator
implementations are currently available in the library:
ArenaPoolAllocator:
Allocates elements in a stack-like manner. Implements the resetTo
operation and an iterator, but does not implement free
.ArenaHeapAllocator:
An Allocator that allows elements to be individually freed. Implements free
, but not resetTo
nor an iterator. This Allocator requires maintaining a pointer with each free element. By default, this pointer is kept outside the element, increasing the effective size per element. However, if part of the element may be overwritten while it is free, then the allocator may be configured to have this pointer overlap part of the element.Allocator
objects are grouped into Arenas
. Each Arena
contains a vector of Allocator
objects. Each distinct Allocator
type is assigned an index into this vector; these indices are globally unique. An Arena
is associated with a ArenaHeader
, which maintains a notion of the ‘current’ Arena
; the ArenaHeader
holds a reference to the Allocator
vector of the current Arena
. An Arena
has a makeCurrent
operation to nominate it as the current Arena
for its ArenaHeader
. A helper class Arena::Push
is provided to change the current Arena
in a stack-like manner. An Arena
also has operations to reset
or erase
all of its Allocators
, as well as for summing statistics over them all. An Arena
also has a name, which is used in printing statistics reports.
The object that the application uses to allocate memory is provided by the Handle
classes. These are templated on the type being allocated as well as on the underlying Allocator
class. A Handle
is created by passing in the Arena
(or ArenaHeader
) with which it is created, as well as any optional creation parameters for the Allocator
. The first time a given type is seen, it is assigned an index the the Arena
Allocator
vector. When a Handle
is created, it will look up the proper Allocator
instance in the current Arena
, creating it if needed. The Handle
will then forward operations to the underlying Allocator
. The library provides two Handle
implementations:
ArenaHandle:
When this Handle
is used, the element constructor/destructor are expected to be called every time an element is allocated/freed by the application. The allocate
method returns a void*
; it is expected that this will then be used in a placement new. The destructor will be called by the library when elements are freed.Handle
allows ‘caching’ already-constructed objects, such that the constructor is run only when the element's memory is first allocated from the system, and the destructor is run only when the element's memory is released back to the system. The allocate
method thus returns an already-initialized T*
. An optional clear
function may be called when the element is freed by the application.An example of the basic usage might be something like this.
See also the unit tests for the Handle classes.
Definition in file Arena.h.