www.digitalmars.com

D Programming Language 2.0

Last update Sat Mar 26 22:54:08 2011

core.tempalloc

This module will eventually be submitted for review and inclusion in core.memory. No synopsis is included since it will likely not be its own module. For now I named it core.tempalloc just to make DDoc generate Phobos-style documentation for it. This is only a provisional name.

Author:
David Simcha

License:
Boost License 1.0

T[] newVoid(T)(size_t length);
Returns a new T[] allocated on the garbage collected heap without initializing its elements. This can be a useful optimization if every element will be immediately initialized.

Examples:
double[] arr = newVoid!double(100);
assert(arr.length == 100);

void* alignedMalloc(size_t size, bool shouldAddRange = false);
Allocates size bytes on the C heap, aligned on 16-byte boundaries. GC.addRange is called to allow the block to be scanned for pointers by the garbage collector iff shouldAddRange is true.

void alignedFree(void* ptr);
Frees memory allocated by alignedMalloc. ptr must point to the start of the memory block. If shouldAddRange was true when alignedMalloc was called, this function also calls GC.removeRange on the block.

struct TempAlloc;
TempAlloc is a memory allocator based on a thread-local segmented stack. A segmented stack is similar to a regular stack in that memory is allocated and freed in last in, first out order. When memory is requested from a segmented stack, it first checks whether enough space is available in the current segment, and if so increments the stack pointer and returns. If not, a new segment is allocated. When memory is freed, the stack pointer is decremented. If the last segment is no longer in use, it may be returned to where it was allocated from or retained for future use.

TempAlloc has the following advantages compared to allocation on the call stack:

1. Pointers to memory allocated on the TempAlloc stack are still valid when the function they were allocated from returns. Functions can be written to create and return data structures on the TempAlloc stack.

2. Since it is a segmented stack, large allocations can be performed with no danger of stack overflow errors.

It has the following advantages compared to heap allocation:

1. Both allocation and deallocation are extremely fast. Most allocations consist of verifying enough space is available, incrementing a pointer and a performing a few cheap bookkeeping operations. Most deallocations consist decrementing a pointer and performing a few cheap bookkeeping operations.

2. The segmented stack is thread-local, so synchronization is only needed when a segment needs to be allocated or freed.

3. Fragmentation is not an issue when allocating memory on the TempAlloc stack, though it can be an issue when trying to allocate a new segment.

Note:
The first segment of the TempAlloc stack is allocated lazily, so no space is allocated in any thread that does not use TempAlloc.

static void frameInit();
Pushes the current stack position onto an internal bookkeeping stack. A call to frameFree frees all memory allocated since the last call to frameInit.

static void frameFree();
Frees all memory allocated by TempAlloc since the last call to frameInit. This can be used to free all TempAlloc memory allocated within a function upon returning from that function.

Examples:
    void useFrameInit() {
        // Mark the current position.
        TempAlloc.frameInit();

        // Free all memory allocated by this function on exit.
        scope(exit) TempAlloc.frameFree();

        // All of these will be freed when useFrameInit() exits.
        auto ptr1 = TempAlloc.malloc(3);
        auto ptr2 = TempAlloc.malloc(1);
        auto ptr3 = TempAlloc.malloc(4);
    }

static void* malloc(size_t nbytes);
Allocates nbytes bytes on the TempAlloc stack. The last block allocated in the current thread can be freed by calling TempAlloc.free. The memory returned by this function is not scanned for pointers by the garbage collector unless GC.addRange is called.

static void free();
Frees the last block of memory allocated in the current thread by TempAlloc. Since all memory must be allocated and freed in last in first out order within a thread, there's no need to pass a pointer to the block being freed. This bookkeeping is handled internally.

static @property size_t slack();
Returns the maximum number of bytes that may be allocated in the current stack segment.

T[] newStack(T)(size_t size);
Allocates an array with size elements of type T on the TempAlloc stack. For performance reasons, the returned array is not initialized. It is not scanned for pointers by the garbage collector unless GC.addRange is called.

Examples:
double[] arr = newStack!double(100);
assert(arr.length == 100);

CommonType!(staticMap!(ElementType, T))[] stackCat(T...)(T data);
Concatenates any number of arrays of the same type, placing results on the TempAlloc stack. The returned array is not scanned for pointers by the garbage collector unless GC.addRange is called.

Examples:
auto a = [1, 2, 3];
auto b = [4, 5, 6];
auto c = [7, 8, 9];

auto d = stackCat(a, b, c);
assert(d == [1, 2, 3, 4, 5, 6, 7, 8, 9]);

Unqual!(ElementType!(R))[] tempdup(R)(R range);
Copies range to an array. The array will be located on the TempAlloc stack and not scanned for pointers by the garbage collector under either of the following conditions:

1. std.traits.hasIndirections!(ElementType!R) is false, or

2. R is a builtin array. In this case range maintains pointers to all elements at least until tempdup returns, preventing the elements from being freed by the garbage collector. A similar assumption cannot be made for ranges other than builtin arrays.

If neither condition is met, the array is returned on the C heap and GC.addRange is called. In either case, TempAlloc.free or TempAlloc.frameFree will free the array as if it had been allocated on the TempAlloc stack.

Rationale:
The most common reason to call tempdup on an array is to modify its contents inside a function without affecting the caller's view. In this case range is not modified and prevents the elements from being freed by the garbage collector.

immutable string newFrame;
A convenience mixin, equivalent to:

TempAlloc.frameInit();  scope(exit) TempAlloc.frameFree();

Example:
void* useNewFrame() {
    // This will not be freed when useFrameInit() exits.
    auto ptr1 = TempAlloc.malloc(8);

    mixin(newFrame);

    // All of these will be freed when useFrameInit() exits.
    auto ptr2 = TempAlloc.malloc(3);
    auto ptr3 = TempAlloc.malloc(1);
    auto ptr4 = TempAlloc.malloc(4);

    // ptr1 is still valid after useNewFrame() exits.
    return ptr1;
}