stdx.allocator
High-level interface for allocators. Implements bundled allocation/creation
and destruction/deallocation of data including structs and classes,
and also array primitives related to allocation. This module is the entry point
for both making use of allocators and for their documentation.
Discussion
Synopsis:
// Allocate an int, initialize it with 42
int* p = theAllocator.make!int(42);
assert(*p == 42);
// Destroy and deallocate it
theAllocator.dispose(p);
// Allocate using the global process allocator
p = processAllocator.make!int(100);
assert(*p == 100);
// Destroy and deallocate
processAllocator.dispose(p);
// Create an array of 50 doubles initialized to -1.0
double[] arr = theAllocator.makeArray!double(50, -1.0);
// Append two zeros to it
theAllocator.expandArray(arr, 2, 0.0);
// On second thought, take that back
theAllocator.shrinkArray(arr, 2);
// Destroy and deallocate
theAllocator.dispose(arr);
D's allocators have a layered structure in both implementation and documentation:
- A high-level, dynamically-typed layer (described further down in this
module). It consists of an interface called , which concret;
allocators need to implement. The interface primitives themselves are oblivious
to the type of the objects being allocated; they only deal in
void[], by necessity of the interface being dynamic (as opposed to type-parameterized). Each thread has a currentallocatorit uses by default, which is a thread-local variable of type . The process has a global allocator called , also of type . When a new thread is created, is copied into . An application can change the objects to which these references point. By default, at application startup, refers to an object that uses D's garbage collected heap. This layer also include high-level functions such as and that comfortably allocate/create and respectively destroy/deallocate objects. This layer is all needed for most casual uses of allocation primitives. - A mid-level, statically-typed layer for assembling several allocators into one. It uses properties of the type of the objects being created to route allocation requests to possibly specialized allocators. This layer is relatively thin and implemented and documented in the module. It allows an interested user to e.g. use different allocators for arrays versus fixed-sized objects, to the end of better overall performance.
- A low-level collection of highly generic heap building blocks
Lego-like pieces that can be used to assemble application-specific allocators.
The real allocation smarts are occurring at this level. This layer is of
interest to advanced applications that want to configure their own allocators.
A good illustration of typical uses of these building blocks is module which defines a collection of frequently-
used preassembled
allocatorobjects. The implementation and documentation entry point is . By design, the primitives of the static interface have the same signatures as the primitives but are for the most part optional and driven by static introspection. The parameterized class offers an immediate and useful means to package a static low-level allocator into an implementation of . - Core allocator objects that interface with D's garbage collected heap
(), the C
mallocfamily (), and the OS (). Most custom allocators would ultimately obtain memory from one of these core allocators.
As of this time, is not integrated with D's built-in operators that allocate memory, such as
new, array literals, or
array concatenation operators. That means is
opt-inapplications need to make explicit use of it.
For casual creation and disposal of dynamically-allocated objects, use , , and the array-specific functions , , and . These use by default D's garbage collected heap, but open the application to better configuration options. These primitives work either with
theAllocator but also with any allocator obtained
by combining heap building blocks. For example:
void fun(size_t n) { // Use the current allocator int[] a1 = theAllocator.makeArray!int(n); scope(exit) theAllocator.dispose(a1); ... }
To experiment with alternative allocators, set for the current thread. For example, consider an application that allocates many 8-byte objects. These are not well supported by the default allocator, so a would be recommended. To install one in
main, the application would use:
void main() { import stdx.allocator.building_blocks.free_list : FreeList; theAllocator = allocatorObject(FreeList!8()); ... }
As with any global resource, setting
theAllocator and processAllocator
should not be done often and casually. In particular, allocating memory with
one allocator and deallocating with another causes undefined behavior.
Typically, these variables are set during application initialization phase and
last through the application.
To avoid this, long-lived objects that need to perform allocations, reallocations, and deallocations relatively often may want to store a reference to the allocator object they use throughout their lifetime. Then, instead of using
theAllocator for internal allocation-related tasks, they'd use the
internally held reference. For example, consider a user-defined hash table:
struct HashTable { private IAllocator _allocator; this(size_t buckets, IAllocator allocator = theAllocator) { this._allocator = allocator; ... } // Getter and setter IAllocator allocator() { return _allocator; } void allocator(IAllocator a) { assert(empty); _allocator = a; } }
Following initialization, the
HashTable object would consistently use its
object for acquiring memory. Furthermore, setting
to point to a different allocator should be legal but
only if the object is empty; otherwise, the object wouldn't be able to
deallocate its existing state.
Allocators assembled from the heap building blocks don't need to go through
IAllocator to be usable. They have the same primitives as IAllocator and
they work with , , etc. So it
suffice to create allocator objects wherever fit and use them appropriately:
void fun(size_t n) { // Use a stack-installed allocator for up to 64KB StackFront!65536 myAllocator; int[] a2 = myAllocator.makeArray!int(n); scope(exit) myAllocator.dispose(a2); ... }
In this case,
myAllocator does not obey the IAllocator interface, but
implements its primitives so it can work with makeArray by means of duck
typing.
One important thing to note about this setup is that statically-typed assembled allocators are almost always faster than allocators that go through
IAllocator. An important rule of thumb is: "assemble allocator first, adapt
to IAllocator after". A good allocator implements intricate logic by means of
template assembly, and gets wrapped with IAllocator (usually by means of
) only once, at client level.
License
.
Source:
-
Declaration
interfaceIAllocator;Dynamic allocator interface. Code that defines allocators ultimately implements this interface. This should be used wherever a uniform type is required for encapsulating various allocator implementations.
Discussion
Composition of allocators is not recommended at this level due to inflexibility of dynamic interfaces and inefficiencies caused by cascaded multiple calls. Instead, compose allocators using the static interface defined in , then adapt the composed allocator to
(possibly by using below).IAllocator
Methods returning return upon success, upon failure, and if the primitive is not implemented by the allocator instance.-
Declaration
abstract @property uintalignment();Returns the
alignmentoffered. -
Declaration
abstract size_tgoodAllocSize(size_ts);Returns the good allocation size that guarantees zero internal fragmentation.
-
Declaration
abstract void[]allocate(size_t, TypeInfoti= null);Allocates
nbytes of memory. -
Declaration
abstract void[]alignedAllocate(size_tn, uinta);Allocates
bytes of memory with specified alignmentn. Implementations that do not support this primitive should always returnanull. -
Declaration
abstract void[]allocateAll();Allocates and returns all memory available to this allocator. Implementations that do not support this primitive should always return
null. -
Declaration
abstract boolexpand(ref void[], size_t);Expands a memory block in place and returns
trueif successful. Implementations that don't support this primitive should always returnfalse. -
Declaration
abstract boolreallocate(ref void[], size_t);Reallocates a memory block.
-
Declaration
abstract boolalignedReallocate(ref void[]b, size_tsize, uintalignment);Reallocates a memory block with specified
alignment. -
Declaration
abstract Ternaryowns(void[]b);Returns if the allocator
owns, if the allocator doesn't own , and if ownership cannot be determined. Implementations that don't support this primitive should always returnTernary.unknown. -
Declaration
abstract TernaryresolveInternalPointer(const void*p, ref void[]result);Resolves an internal pointer to the full block allocated. Implementations that don't support this primitive should always return
Ternary.unknown. -
Declaration
abstract booldeallocate(void[]b);Deallocates a memory block. Implementations that don't support this primitive should always return
false. A simple way to check that an allocator supports deallocation is to call . -
Declaration
abstract booldeallocateAll();Deallocates all memory. Implementations that don't support this primitive should always return
false. -
Declaration
abstract Ternaryempty();Returns if no memory is currently allocated from this allocator, if some allocations are currently active, or if not supported.
-
-
Declaration
interfaceISharedAllocator;Dynamic shared allocator interface. Code that defines allocators shareable across threads ultimately implements this interface. This should be used wherever a uniform type is required for encapsulating various allocator implementations.
Discussion
Composition of allocators is not recommended at this level due to inflexibility of dynamic interfaces and inefficiencies caused by cascaded multiple calls. Instead, compose allocators using the static interface defined in , then adapt the composed allocator to
(possibly by using below).ISharedAllocator
Methods returning return upon success, upon failure, and if the primitive is not implemented by the allocator instance.-
Declaration
abstract shared @property uintalignment();Returns the
alignmentoffered. -
Declaration
abstract shared size_tgoodAllocSize(size_ts);Returns the good allocation size that guarantees zero internal fragmentation.
-
Declaration
abstract shared void[]allocate(size_t, TypeInfoti= null);Allocates
nbytes of memory. -
Declaration
abstract shared void[]alignedAllocate(size_tn, uinta);Allocates
bytes of memory with specified alignmentn. Implementations that do not support this primitive should always returnanull. -
Declaration
abstract shared void[]allocateAll();Allocates and returns all memory available to this allocator. Implementations that do not support this primitive should always return
null. -
Declaration
abstract shared boolexpand(ref void[], size_t);Expands a memory block in place and returns
trueif successful. Implementations that don't support this primitive should always returnfalse. -
Declaration
abstract shared boolreallocate(ref void[], size_t);Reallocates a memory block.
-
Declaration
abstract shared boolalignedReallocate(ref void[]b, size_tsize, uintalignment);Reallocates a memory block with specified
alignment. -
Declaration
abstract shared Ternaryowns(void[]b);Returns if the allocator
owns, if the allocator doesn't own , and if ownership cannot be determined. Implementations that don't support this primitive should always returnTernary.unknown. -
Declaration
abstract shared TernaryresolveInternalPointer(const void*p, ref void[]result);Resolves an internal pointer to the full block allocated. Implementations that don't support this primitive should always return
Ternary.unknown. -
Declaration
abstract shared booldeallocate(void[]b);Deallocates a memory block. Implementations that don't support this primitive should always return
false. A simple way to check that an allocator supports deallocation is to call . -
Declaration
abstract shared booldeallocateAll();Deallocates all memory. Implementations that don't support this primitive should always return
false. -
Declaration
abstract shared Ternaryempty();Returns if no memory is currently allocated from this allocator, if some allocations are currently active, or if not supported.
-
-
Declaration
nothrow @nogc @property @safe IAllocatortheAllocator();
nothrow @nogc @property @safe voidtheAllocator(IAllocatora);Gets/sets the allocator for the current thread. This is the default allocator that should be used for allocating thread-local memory. For allocating memory to be shared across threads, use (below). By default, ultimately fetches memory from , which in turn uses the garbage collected heap.
Examples
// Install a new allocator that is faster for 128-byte allocations. import stdx.allocator.building_blocks.free_list : FreeList; import stdx.allocator.gc_allocator : GCAllocator; auto oldAllocator = theAllocator; scope(exit) theAllocator = oldAllocator; theAllocator = allocatorObject(FreeList!(GCAllocator, 128)()); // Use the now changed allocator to allocate an array const ubyte[] arr = theAllocator.makeArray!ubyte(128); assert(arr.ptr); //...
-
Declaration
@property shared(ISharedAllocator)processAllocator();
@property voidprocessAllocator(shared ISharedAllocatora);Gets/sets the allocator for the current process. This allocator must be used for allocating memory shared across threads. Objects created using this allocator can be cast to .
-
Declaration
automake(T, Allocator, A...)(auto ref Allocatoralloc, auto ref Aargs);Dynamically allocates (using ) and then creates in the memory allocated an object of type , using (if any) for its initialization. Initialization occurs in the memory allocated and is otherwise semantically the same as . (Note that using creates a pointer to an (empty) array of s, not an array. To use an allocator to allocate and initialize an array, use described below.)
Parameters
TType of the object being created.
AllocatorallocThe allocator used for getting the needed memory. It may be an object implementing the static interface for allocators, or an reference.
AargsOptional arguments used for initializing the created object. If not present, the object is default constructed.
Return Value
If is a class type, returns a reference to the created object. Otherwise, returns a pointing to the created object. In all cases, returns if allocation failed.
Throws
If 's constructor throws, deallocates the allocated memory and propagates the exception.
Examples
// Dynamically allocate one integer const int* p1 = theAllocator.make!int; // It's implicitly initialized with its .init value assert(*p1 == 0); // Dynamically allocate one double, initialize to 42.5 const double* p2 = theAllocator.make!double(42.5); assert(*p2 == 42.5); // Dynamically allocate a struct static struct Point { int x, y, z; } // Use the generated constructor taking field values in order const Point* p = theAllocator.make!Point(1, 2); assert(p.x == 1 && p.y == 2 && p.z == 0); // Dynamically allocate a class object static class Customer { uint id = uint.max; this() {} this(uint id) { this.id = id; } // ... } Customer cust = theAllocator.make!Customer; assert(cust.id == uint.max); // default initialized cust = theAllocator.make!Customer(42); assert(cust.id == 42); // explicit passing of outer pointer static class Outer { int x = 3; class Inner { auto getX() { return x; } } } auto outer = theAllocator.make!Outer(); auto inner = theAllocator.make!(Outer.Inner)(outer); assert(outer.x == inner.getX);
-
Declaration
T[]makeArray(T, Allocator)(auto ref Allocatoralloc, size_tlength);
T[]makeArray(T, Allocator)(auto ref Allocatoralloc, size_tlength, auto ref Tinit);
Unqual!(ElementEncodingType!R)[]makeArray(Allocator, R)(auto ref Allocatoralloc, Rrange) if (isInputRange!R && !isInfinite!R);
T[]makeArray(T, Allocator, R)(auto ref Allocatoralloc, Rrange) if (isInputRange!R && !isInfinite!R);Create an array of with elements using . The array is either default-initialized, filled with copies of , or initialized with values fetched from
.rangeParameters
Telement type of the array being created
Allocatorallocthe allocator used for getting memory
size_tlengthlengthof the newly created arrayTinitelement used for filling the array
Rrangerangeused for initializing the array elementsReturn Value
The newly-created array, or if either was or allocation failed.
Throws
The first two overloads throw only if
's primitives do. The overloads that involve copy initialization deallocate memory and propagate the exception if the copy operation throws.allocExamples
import std.algorithm.comparison : equal; static void test(T)() { T[] a = theAllocator.makeArray!T(2); assert(a.equal([0, 0])); a = theAllocator.makeArray!T(3, 42); assert(a.equal([42, 42, 42])); import std.range : only; a = theAllocator.makeArray!T(only(42, 43, 44)); assert(a.equal([42, 43, 44])); } test!int(); test!(shared int)(); test!(const int)(); test!(immutable int)();
-
Declaration
boolexpandArray(T, Allocator)(auto ref Allocatoralloc, ref T[]array, size_tdelta);
boolexpandArray(T, Allocator)(auto ref Allocatoralloc, ref T[]array, size_tdelta, auto ref Tinit);
boolexpandArray(T, Allocator, R)(auto ref Allocatoralloc, ref T[]array, Rrange) if (isInputRange!R);Grows by appending more elements. The needed memory is allocated using . The extra elements added are either default- initialized, filled with copies of , or initialized with values fetched from
.rangeParameters
Telement type of the
arraybeing createdAllocatorallocthe allocator used for getting memory
T[]arraya reference to the
arraybeing grownsize_tdeltanumber of elements to add (upon success the new length of is )
Tinitelement used for filling the
arrayRrangerangeused for initializing thearrayelementsReturn Value
upon success, if memory could not be allocated. In the latter case is left unaffected.
Throws
The first two overloads throw only if
's primitives do. The overloads that involve copy initialization deallocate memory and propagate the exception if the copy operation throws.allocExamples
auto arr = theAllocator.makeArray!int([1, 2, 3]); assert(theAllocator.expandArray(arr, 2)); assert(arr == [1, 2, 3, 0, 0]); import std.range : only; assert(theAllocator.expandArray(arr, only(4, 5))); assert(arr == [1, 2, 3, 0, 0, 4, 5]);
-
Declaration
boolshrinkArray(T, Allocator)(auto ref Allocatoralloc, ref T[]array, size_tdelta);Shrinks an
arrayby elements.Discussion
If , does nothing and returns
false. Otherwise, destroys the last elements in thearrayand then reallocates thearray's buffer. If reallocation fails, fills thearraywith default-initialized data.Parameters
Telement type of the
arraybeing createdAllocatorallocthe allocator used for getting memory
T[]arraya reference to the
arraybeing shrunksize_tdeltanumber of elements to remove (upon success the new length of is )
Return Value
trueupon success,falseif memory could not be reallocated. In the latter case, the slice is left with default-initialized elements.Throws
The first two overloads throw only if
's primitives do. The overloads that involve copy initialization deallocate memory and propagate the exception if the copy operation throws.allocExamples
int[] a = theAllocator.makeArray!int(100, 42); assert(a.length == 100); assert(theAllocator.shrinkArray(a, 98)); assert(a.length == 2); assert(a == [42, 42]);
-
Declaration
voiddispose(A, T)(auto ref Aalloc, auto ref T*p);
voiddispose(A, T)(auto ref Aalloc, auto ref Tp) if (is(T == class) || is(T == interface));
voiddispose(A, T)(auto ref Aalloc, auto ref T[]array);Destroys and then deallocates (using ) the object pointed to by a pointer, the class object referred to by a or reference, or an entire
array. It is assumed the respective entities had been allocated with the same allocator. -
Declaration
automakeMultidimensionalArray(T, Allocator, size_t N)(auto ref Allocatoralloc, size_t[N]lengths...);Allocates a multidimensional array of elements of type T.
Parameters
Nnumber of dimensions
Telement type of an element of the multidimensional arrat
Allocatorallocthe allocator used for getting memory
size_t[N]lengthsstatic array containing the size of each dimension
Return Value
An N-dimensional array with individual elements of type T.
Examples
import stdx.allocator.mallocator : Mallocator; auto mArray = Mallocator.instance.makeMultidimensionalArray!int(2, 3, 6); // deallocate when exiting scope scope(exit) { Mallocator.instance.disposeMultidimensionalArray(mArray); } assert(mArray.length == 2); foreach (lvl2Array; mArray) { assert(lvl2Array.length == 3); foreach (lvl3Array; lvl2Array) assert(lvl3Array.length == 6); }
-
Declaration
voiddisposeMultidimensionalArray(T, Allocator)(auto ref Allocatoralloc, auto ref T[]array);Destroys and then deallocates a multidimensional
array, assuming it was created with makeMultidimensionalArray and the same allocator was used.Parameters
Telement type of an element of the multidimensional
arrayAllocatorallocthe allocator used for getting memory
T[]arraythe multidimensional
arraythat is to be deallocatedExamples
struct TestAllocator { import stdx.allocator.common : platformAlignment; import stdx.allocator.mallocator : Mallocator; alias allocator = Mallocator.instance; private static struct ByteRange { void* ptr; size_t length; } private ByteRange[] _allocations; enum uint alignment = platformAlignment; void[] allocate(size_t numBytes) { auto ret = allocator.allocate(numBytes); _allocations ~= ByteRange(ret.ptr, ret.length); return ret; } bool deallocate(void[] bytes) { import std.algorithm.mutation : remove; import std.algorithm.searching : canFind; bool pred(ByteRange other) { return other.ptr == bytes.ptr && other.length == bytes.length; } assert(_allocations.canFind!pred); _allocations = _allocations.remove!pred; return allocator.deallocate(bytes); } ~this() { assert(!_allocations.length); } } TestAllocator allocator; auto mArray = allocator.makeMultidimensionalArray!int(2, 3, 5, 6, 7, 2); allocator.disposeMultidimensionalArray(mArray);
-
Declaration
CAllocatorImpl!AallocatorObject(A)(auto ref Aa) if (!isPointer!A);
CAllocatorImpl!(A, Yes.indirect)allocatorObject(A)(A*pa);Returns
adynamically-typed built aroundagiven statically- typed allocator of type . Passingapointer to the allocator createsadynamic allocator around the allocator pointed to by the pointer, without attempting to copy or move it. Passing the allocator by value or reference behaves as follows.Discussion
- If has no state, the resulting object is allocated in static shared storage.
- If has state and is copyable, the result will store
acopy of it within. The result itself is allocated in its own statically-typed allocator. - If has state and is not copyable, the result will move the passed-in argument into the result. The result itself is allocated in its own statically-typed allocator.
Examples
import stdx.allocator.mallocator : Mallocator; IAllocator a = allocatorObject(Mallocator.instance); auto b = a.allocate(100); assert(b.length == 100); assert(a.deallocate(b)); // The in-situ region must be used by pointer import stdx.allocator.building_blocks.region : InSituRegion; auto r = InSituRegion!1024(); a = allocatorObject(&r); b = a.allocate(200); assert(b.length == 200); // In-situ regions can deallocate the last allocation assert(a.deallocate(b));
-
Declaration
shared(CSharedAllocatorImpl!A)sharedAllocatorObject(A)(auto ref Aa) if (!isPointer!A);
shared(CSharedAllocatorImpl!(A, Yes.indirect))sharedAllocatorObject(A)(A*pa);Returns
adynamically-typed built aroundagiven statically- typed allocator of type . Passingapointer to the allocator createsadynamic allocator around the allocator pointed to by the pointer, without attempting to copy or move it. Passing the allocator by value or reference behaves as follows.Discussion
- If has no state, the resulting object is allocated in static shared storage.
- If has state and is copyable, the result will store
acopy of it within. The result itself is allocated in its own statically-typed allocator. - If has state and is not copyable, the result will move the passed-in argument into the result. The result itself is allocated in its own statically-typed allocator.
-
Declaration
classCAllocatorImpl(Allocator, Flag!"indirect" indirect = No.indirect): IAllocator;Implementation of
IAllocatorusingAllocator. This adapts a statically-built allocator type toIAllocatorthat is directly usable by non-templated code.Discussion
Usually
is used indirectly by calling .CAllocatorImpl-
Declaration
ref Allocatorimpl();The implementation is available as a public member.
-
Declaration
this(Allocator*pa);The implementation is available as a public member.
-
Declaration
@property uintalignment();Returns
impl..alignment -
Declaration
size_tgoodAllocSize(size_ts);Returns
impl..goodAllocSize(s) -
Declaration
void[]allocate(size_ts, TypeInfoti= null);Returns
impl..allocate(s) -
Declaration
void[]alignedAllocate(size_ts, uinta);If
impl.exists, calls it and returns the result. Otherwise, always returnsalignedAllocatenull. -
Declaration
Ternaryowns(void[]b);If
Allocatorimplements, forwards to it. Otherwise, returnsownsTernary.unknown. -
Declaration
boolexpand(ref void[]b, size_ts);Returns if defined,
falseotherwise. -
Declaration
boolreallocate(ref void[]b, size_ts);Returns .
-
Declaration
boolalignedReallocate(ref void[]b, size_ts, uinta);Forwards to
impl.if defined,alignedReallocatefalseotherwise. -
Declaration
booldeallocate(void[]b);If
impl.is not defined, returnsdeallocatefalse. Otherwise it forwards the call. -
Declaration
booldeallocateAll();Calls
impl.and returns the result if defined, otherwise returnsdeallocateAll()false. -
Declaration
Ternaryempty();Forwards to
impl.if defined, otherwise returnsempty()Ternary.unknown. -
Declaration
void[]allocateAll();Returns
impl.if present,allocateAll()nullotherwise.
-
-
Declaration
classCSharedAllocatorImpl(Allocator, Flag!"indirect" indirect = No.indirect): ISharedAllocator;Implementation of
ISharedAllocatorusingAllocator. This adapts a statically-built, shareable across threads, allocator type toISharedAllocatorthat is directly usable by non-templated code.Discussion
Usually
is used indirectly by calling .CSharedAllocatorImpl-
Declaration
shared ref Allocatorimpl();The implementation is available as a public member.
-
Declaration
shared this(Allocator*pa);The implementation is available as a public member.
-
Declaration
shared @property uintalignment();Returns
impl..alignment -
Declaration
shared size_tgoodAllocSize(size_ts);Returns
impl..goodAllocSize(s) -
Declaration
shared void[]allocate(size_ts, TypeInfoti= null);Returns
impl..allocate(s) -
Declaration
shared void[]alignedAllocate(size_ts, uinta);If
impl.exists, calls it and returns the result. Otherwise, always returnsalignedAllocatenull. -
Declaration
shared Ternaryowns(void[]b);If
Allocatorimplements, forwards to it. Otherwise, returnsownsTernary.unknown. -
Declaration
shared boolexpand(ref void[]b, size_ts);Returns if defined,
falseotherwise. -
Declaration
shared boolreallocate(ref void[]b, size_ts);Returns .
-
Declaration
shared boolalignedReallocate(ref void[]b, size_ts, uinta);Forwards to
impl.if defined,alignedReallocatefalseotherwise. -
Declaration
shared booldeallocate(void[]b);If
impl.is not defined, returnsdeallocatefalse. Otherwise it forwards the call. -
Declaration
shared booldeallocateAll();Calls
impl.and returns the result if defined, otherwise returnsdeallocateAll()false. -
Declaration
shared Ternaryempty();Forwards to
impl.if defined, otherwise returnsempty()Ternary.unknown. -
Declaration
shared void[]allocateAll();Returns
impl.if present,allocateAll()nullotherwise.
-