ATLAS Offline Software
Loading...
Searching...
No Matches
Arena.h File Reference

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>
Include dependency graph for Arena.h:
This graph shows which files directly or indirectly include this file:

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

namespace  SG
 Forward declaration.

Detailed Description

Collection of memory allocators with a common lifetime, plus subsystem summary.

Author
scott snyder
Date
May 2007

The Arena classes provide a framework for memory allocation. It supports the following general features:

  • Segregated storage. Objects of identical type are grouped together. Memory is allocated from the system in large blocks and carved up into the individual objects. This allows eliminating malloc overhead and it helps with reducing problems due to heap fragmentation.
  • Objects may be ‘cached’: the object constructor is run only when the memory is first allocated. If it is freed and then reallocated by the application, the destructor/constructor calls may be eliminated.
  • Memory allocations of similar lifetimes may be grouped together in `‘Arenas’'. All memory in a given Arena may be freed at once.
  • We attempt to make individual object allocation and deallocation very fast. The code for the ‘common’ case can be entirely inlined, and should compile to a handful of instructions.
  • We keep statistics about the amount of memory allocated per type per Arena.

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.

  • An element is an individual piece of memory that the application requests.
  • A block is a piece of memory allocated from the system It will usually be divided up into individual elements.
  • An Allocator is the fundamental memory allocator, managing storage for a single type of object. Memory allocated from the system associated with a single Allocator. The Allocator classes themselves do not depend on the types being allocated; however, functions operating on these objects, such as constructors and destructors, may be given to the Allocator to be called at an appropriate time. Multiple Allocator implementations may be available, implementing different strategies.
  • An Arena is a group of Allocators, which share a common lifetime. The memory allocated by all Allocators in an Arena may be freed in a single operation.
  • An ArenaHeader represents a group of Arenas. One Arena is considered the ‘current’ Arena; it is the one from which memory allocations will be made. Arenas within the group may be made current in a stack-like manner.
  • 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:

  • The constructor function is called when an element is first allocated from the system.
  • The destructor function is called just before an element's memory is released back to the system.
  • The clear function is called after the application frees an element.

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.
  • An iterator, which iterates over all allocated blocks.

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.
  • @ ArenaCachingHandle: This 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.

class Example { ...
SG::Arena m_arena;
...};
Example::Example()
// Associates with the default ArenaHeader.
: m_arena ("myarena") { ...
...}
ret Example::execute() { ...
SG::Arena::Push push (m_arena);
MyObj* obj = handle.allocate();
...}
ret Example::newEvent() { ...
m_arena.reset();
... }
User interface for allocating memory that caches constructed objects.
pointer allocate()
Allocate a new element.
Helper class for making Arena instances current in a stack-like manner.
Definition Arena.h:273
Collection of memory allocators with a common lifetime,.
Definition Arena.h:238

See also the unit tests for the Handle classes.

Definition in file Arena.h.