2 * Naive Garbage Collector implementation.
4 * This module implements a Naive Garbage Collector. The idea behind this
5 * implementation is to document all the bookkeeping and considerations that
6 * have to be taken in order to implement a garbage collector for D.
8 * The garbage collector algorithm itself is extremely simple to make it
9 * easier to focus on the specifics of D. A completely naive mark and sweep
10 * algorithm is used, with a recursive mark phase. The code is extremely
11 * inefficient in order to keep it clean, and easy to read and understand.
13 * The implementation is split in several modules to ease the reading even
14 * more. All architecture/compiler specific code is done in the arch module,
15 * in order to avoid confusing version statements all over the places. The
16 * cell module has all the code related to the memory cells header. dynarray
17 * is another support module which holds the implementation of a simple
18 * dynamic array used to store root pointers and ranges. The list module holds
19 * a simple singly linked list (of cells) implementation to store the live and
20 * free lists. Finally, the iface module is the one with the C interface to
21 * comply with the Tango/Druntime GC specification.
23 * Copyright: Public Domain
24 * License: Public Domain
25 * Authors: Leandro Lucarella <llucax@gmail.com>
33 import gc.cell: Cell, BlkAttr, op_apply_ptr_range;
35 import gc.dynarray: DynArray;
36 import gc.arch: push_registers, pop_registers;
39 import cstring = tango.stdc.string;
40 import mman = tango.stdc.posix.sys.mman;
41 // XXX: missing in Tango 0.99.8 for Linux
42 extern (C) int mprotect(void*, size_t, int);
47 * These are external functions coming from the D/Tango runtime. It's pretty
48 * intuitive what they do based on their names, for more details please
49 * refer to the functions documentation.
51 alias void delegate(void*, void*) mark_function;
52 extern (C) void onOutOfMemoryError();
53 extern (C) void rt_finalize(void* p, bool det=true);
54 extern (C) void rt_scanStaticData(mark_function mark);
55 extern (C) void thread_init();
56 extern (C) bool thread_needLock();
57 extern (C) void thread_suspendAll();
58 extern (C) void thread_resumeAll();
59 extern (C) void thread_scanAll(mark_function mark, void* stack_top=null);
62 * A range of memory that should be scanned for pointers.
64 * This object is iterable, yielding a pointer (void*) for each iteration.
69 /// Beginning of the memory range
72 /// End of the memory range
75 /// Iterate over a memory range applying dg to its elements
76 int opApply(int delegate(ref void*) dg)
78 return op_apply_ptr_range(this.from, this.to, dg);
88 * Information on a block of memory.
90 * This is part of the GC specification, it's used for the query() method.
92 * Standards: Tango/Druntime specs
97 /// Base address of the block
100 /// Size of the block (this is the total capacity, not the requested size)
104 * Memory block attributes
106 * See_Also: cell.BlkAttr for possible values
116 * This object contains the whole GC implementation. This is instantiated in
117 * the iface module as a global variable to provide the GC services.
119 * This implementation is designed to be extremely simple. The algorithm
120 * implemented is the most basic stop-the-world mark-sweep known.
122 * Memory is organized in cells. Each cell has a header where all the
123 * bookkeeping information is stored (like the mark bit, cell attributes,
124 * capacity, etc.), and the memory allocated for the requested memory itself.
126 * Two lists of cells are kept: free list and live list.
128 * The free list store cells known not to be referenced by the program. The
129 * live list stores cells that were referenced by the program at the end of
130 * the last collection (and just allocated cells).
132 * The root set is composed by several elements:
136 * $(LI Threads stack)
138 * $(LI Root pointers)
142 * Root pointers and ranges are user-defined.
147 * $(LI cell.Cell for the cell header layout)
148 * $(LI collect() for the main collection algorithm)
158 /// List of free cells.
161 /// List of live cells.
164 /// Single root pointers.
165 DynArray!(void*) root_pointers;
168 DynArray!(RootRange) root_ranges;
171 * "Flag" to indicate when the GC is disabled.
173 * This is a number because calls to enable() and disable() can be
174 * recursive. The number of calls to enable() should match the number of
175 * calls to disable(), though, if you want the GC to be effectively
181 * Remove the mark bit to all the live cells.
183 * This is done before starting the mark phase.
188 * $(LI collect() for the main collect algorithm)
189 * $(LI mark_all() for details on the marking phase)
194 foreach (cell; this.live_list)
199 * Mark all live data (pausing all threads)
201 * This methods start marking following all the known roots:
205 * $(LI Threads stack)
207 * $(LI Root pointers)
211 * Note that the registers are pushed into the stack to get scanned.
213 * This is the complete mark phase. The algorithm roughly does:
216 * $(LI Push registers into the stack)
217 * $(LI Pause all threads (but the current one, of course))
218 * $(LI Scan the static data)
219 * $(LI Scan all threads stack)
220 * $(LI Scan the root pointers and ranges)
221 * $(LI Resume all threads)
222 * $(LI Pop the registers from the stack)
229 * $(LI collect() for the main collect algorithm)
230 * $(LI mark() for details on the marking algorithm)
231 * $(LI sweep() for details on the sweep phase)
237 mixin (push_registers("stack_top"));
239 rt_scanStaticData(&mark_range);
240 thread_scanAll(&mark_range, stack_top);
241 foreach (ptr; this.root_pointers) {
244 foreach (range; this.root_ranges) {
245 this.mark_range(range.from, range.to);
248 mixin (pop_registers("stack_top"));
252 * Wrapper for mark() over a range, needed by some runtime functions.
254 * This function is used as a delegate to be passed to rt_scanStaticData()
255 * and thread_scanAll(), because they expect a function taking 2 pointers.
257 * This extremely inefficient on purpose. The goal of this implementation
258 * is simplicity, nor performance.
262 * $(LI mark() for details on the marking algorithm)
265 void mark_range(void* from, void* to)
267 foreach (ptr; RootRange(from, to))
272 * Mark all cells accessible from a pointer.
274 * This is the mark algorithm itself. It's recursive and dumb as a log. No
275 * care is taken in regards to stack overflows. This is the first example
278 * Marking is done with all threads stopped.
282 * $(LI collect() for the main collect algorithm)
283 * $(LI mark_all() for details on the marking phase)
284 * $(LI sweep() for details on the sweep phase)
289 Cell* cell = Cell.from_ptr(this.addrOf(ptr));
294 if (cell.has_pointers) {
302 * Move unreferenced live objects to the free list (calling finalizers).
304 * This is the sweep phase. It's very simple, it just searches the live
305 * list and move unmarked cells to the free list. This function is in
306 * charge of calling finalizers too, through the rt_finalize() runtime
309 * Sweeping is done concurrently with the mutator threads.
313 * $(LI collect() for the main collect algorithm)
314 * $(LI mark_all() for details on the marking phase)
319 foreach (cell; this.live_list) {
321 this.live_list.unlink(cell);
322 if (cell.has_finalizer)
323 rt_finalize(cell.ptr, false);
324 // Forbid the mutator read/write cell data
325 int r = mprotect(cast(byte*) cell + 4096, cell.capacity,
328 this.free_list.link(cell);
339 * This initializes the thread library too, as requested by the
340 * Tango/Druntime specs.
351 * Finalization of unreferenced cells is not mandatory by the specs.
352 * This implementation guarantees that all finalizers are called, at least
353 * at program exit (i.e. at GC termination).
355 * The specs says that "objects referenced from the data segment never get
356 * collected by the GC". While this is true for this implementation,
357 * finalizers are called for objects referenced from the data segment at
360 * There could be some problems with this, in very strange situations. For
361 * a more complete discussion about the topic please take a look at the
362 * bug 2858: http://d.puremagic.com/issues/show_bug.cgi?id=2858
366 foreach (cell; this.live_list)
367 if (cell.has_finalizer)
368 rt_finalize(cell.ptr, false);
369 // Let the OS free the memory on exit.
375 * When the GC is enabled, a collection is triggered when malloc() can't
376 * find room in the free list to fulfill the requested size.
378 * enable() and disable() can be called recursively. The number of calls
379 * to enable() should match the number of calls to disable(), though, if
380 * you want the GC to be effectively enabled again.
382 * See_Also: disable()
386 assert (this.disabled > 0);
398 assert (this.disabled > 0);
402 * Run a GC collection in order to find unreferenced objects.
404 * This is the simplest stop-the-world mark-sweep algorithm ever. It first
405 * removes the mark bit from all the live cells, then it marks the cells
406 * that are reachable through the root set (static data, stack, registers
407 * and custom root), and finally sweeps the live list looking for unmarked
410 * The world is stopped only for the mark phase.
414 * $(LI mark_all() for details on the marking phase)
415 * $(LI sweep() for details on the sweep phase)
426 * Minimize free space usage.
428 * This method returns to the OS memory that is not longer used by
429 * the program. Usually calling this method manually is not
430 * necessary, because unused cells are recycled for future
431 * allocations. But if there is some small part of the program that
432 * requires a lot of memory and it's known that it won't be used
433 * further, calling this can reduce the memory footprint of the program
434 * considerably (at the expense of some performance lost in future
437 * This implementation just return to the OS all the cells in the free
442 foreach (cell; this.free_list) {
443 this.free_list.unlink(cell);
449 * Get attributes associated to the cell pointed by ptr.
451 * Attributes is a bitmap that can have these values:
454 * $(LI 1: The object stored in the cell has to be finalized)
455 * $(LI 2: The cell should not be scanned for pointers)
456 * $(LI 4: The cell should not be moved during a collection
460 * See_Also: cell.BlkAttr, setAttr(), clrAttr()
462 uint getAttr(void* ptr)
464 auto cell = this.live_list.find(ptr);
471 * Set the attributes of the cell pointed by ptr.
473 * All bits present in attr are set, other bits are untouched. The old
474 * attributes are returned.
476 * See_Also: cell.BlkAttr, getAttr(), clrAttr()
478 uint setAttr(void* ptr, uint attr)
480 auto cell = this.live_list.find(ptr);
482 auto old = cell.attr;
490 * Clear the attributes of the cell pointed by ptr.
492 * All bits present in attr are cleared, other bits are untouched. The old
493 * attributes are returned.
495 * See_Also: cell.BlkAttr, getAttr(), setAttr()
497 uint clrAttr(void* ptr, uint attr)
499 auto cell = this.live_list.find(ptr);
501 auto old = cell.attr;
511 * This is the main allocator of the GC. The algorithm is really
512 * simple. It does a first-fit search in the free list, if no free cell is
513 * found with enough room, it runs a collection and retry (unless the GC
514 * is disabled). If there is no room still, it uses C malloc to allocate
515 * a new cell. If all that fails, then onOutOfMemoryError() runtime
516 * function is called to handle the error.
518 * attr are the attributes to associate to the new cell (see getAttr() for
521 void* malloc(size_t size, uint attr=0)
526 // Find a free cell in the free list with enough space
527 auto cell = this.free_list.pop(size);
531 // No room in the free list found, if the GC is enabled, trigger
532 // a collection and try again
533 if (!this.disabled) {
535 cell = this.free_list.pop(size);
540 // No luck still, allocate a new cell
541 cell = Cell.alloc(size, attr);
546 onOutOfMemoryError();
551 // Allow the mutator to read/write cell data
552 int r = mprotect(cast(byte*) cell + 4096, cell.capacity,
553 mman.PROT_READ | mman.PROT_WRITE);
556 cell.attr = cast(BlkAttr) attr;
559 this.live_list.link(cell);
565 * Allocate memory (set memory to zero).
567 * Same as malloc() but set the allocated memory cell to zero.
569 void* calloc(size_t size, uint attr=0)
574 void* ptr = this.malloc(size, attr);
576 if (ptr !is null) // in case onOutOfMemoryError didn't throw
577 cstring.memset(ptr, 0, size);
585 * This implementation is very simple, if size less or equals than the
586 * cells capacity, the cell's size is changed and the same address is
587 * returned. Otherwise a new cell is allocated using malloc() (this can
588 * trigger a collection), the contents are moved and the old cell is freed.
590 * attr has the same meaning as in malloc().
592 void* realloc(void* ptr, size_t size, uint attr=0)
594 debug (gc_malloc) printf("gc.realloc(%p, %u, %u)\n", ptr, size, attr);
596 // Undercover malloc()
598 return this.malloc(size, attr);
606 auto cell = this.live_list.find(ptr);
607 assert (cell !is null);
609 // We have enough capacity already, just change the size
610 if (cell.capacity >= size) {
612 printf("gc.realloc() - cell has %zu capacity, no need to "
613 "realloc\n", cell.capacity);
618 // We need to move the cell because of the lack of capacity, find
619 // a free cell with the requested capacity (at least)
620 ptr = this.malloc(size, attr);
621 if (ptr is null) // in case onOutOfMemoryError didn't throw
623 Cell* new_cell = Cell.from_ptr(ptr);
624 assert (new_cell !is null);
626 // Move cell attributes and contents
627 new_cell.attr = cell.attr;
628 cstring.memcpy(new_cell.ptr, cell.ptr, cell.size);
637 * Attempt to in-place enlarge a memory block pointed to by ptr.
639 * The memory should be enlarged to at least min_size beyond its current
640 * capacity, up to a maximum of max_size. This does not attempt to move
641 * the memory block (like realloc() does).
644 * 0 if could not extend ptr, total size of entire memory block if
647 size_t extend(void* ptr, size_t min_size, size_t max_size)
649 assert (min_size <= max_size);
650 // There is no possible extension of the capacity for this
656 * Reserve memory to anticipate memory allocations.
658 * This implementation is really dumb, a single cell is allocated with
659 * size bytes. If 2 malloc()s follow a call to reserve(size), requesting
660 * size/2 bytes each, one allocation will still be done (and half the
661 * memory of the first malloc will be wasted =). Since this is a trivial
662 * implementation, we don't care about this.
664 * The actual number of bytes reserved are returned, or 0 on error.
666 size_t reserve(size_t size)
669 auto cell = Cell.alloc(size);
672 // Forbid the mutator read/write cell data
673 int r = mprotect(cast(byte*) cell + 4096, cell.capacity,
676 this.free_list.link(cell);
677 return cell.capacity;
681 * Free unused memory.
683 * This method tells the GC that a cell is not longer used. The GC doesn't
684 * perform any connectivity check, if the cell was referenced by others,
685 * nasty things will happen (much like C/C++).
687 * Note that finalizers are not called by this method. Finalizers are
688 * called by the runtime when the delete operator is used, and the delete
689 * operator calls this method through the runtime.
693 debug (gc_malloc) printf("gc.free(%p)\n", ptr);
698 auto cell = this.live_list.pop(ptr);
699 assert (cell !is null);
701 // Forbid the mutator read/write cell data
702 int r = mprotect(cast(byte*) cell + 4096, cell.capacity,
706 this.free_list.link(cell);
710 * Get the base address of an interior pointer into the GC heap.
712 * If ptr is not pointing into the GC heap null is returned.
714 void* addrOf(void* ptr)
719 bool in_range(Cell* cell)
721 return ptr >= cell.ptr && ptr < (cell.ptr + cell.size);
724 auto cell = this.live_list.find(&in_range);
732 * Return the real size (capacity) for the cell pointed to by ptr.
734 * ptr should be the base address of a heap allocated object, interior
735 * pointers are not supported (use addrOf() if you have an interior
736 * pointer). If this is not true, this method returns 0.
738 * realloc(ptr, sizeOf(ptr), attr) is guaranteed not to allocate/move
741 size_t sizeOf(void* ptr)
743 auto cell = this.live_list.find(ptr);
745 return cell.capacity;
750 * Get information about the cell pointed to by ptr.
752 * ptr should be the base address of a heap allocated object, interior
753 * pointers are not supported (use addrOf() if you have an interior
754 * pointer). If this is not true, this method returns BlkInfo.init.
756 * See BlkInfo for the information provided by this method.
758 BlkInfo query(void* ptr)
762 auto cell = this.live_list.find(ptr);
764 blk_info.base = cell.ptr;
765 blk_info.size = cell.capacity;
766 blk_info.attr = cell.attr;
773 * Add a root pointer to the root set.
775 * This method can be used to register new root to the GC heap. This is
776 * only needed when the user has custom memory that has pointers into the
777 * GC heap (for example for interfacing with C programs, which allocates
778 * memory using malloc() directly).
780 * See_Also: removeRoot(), addRange(), removeRange()
782 void addRoot(void* ptr)
784 this.root_pointers.append(ptr);
788 * Add a root range to the root set.
790 * This method can be used to register new root range (a memory chunk
791 * that should be scanned for pointers into the GC heap). This is
792 * only needed when the user has custom memory that has pointers into the
793 * GC heap (for example for interfacing with C programs, which allocates
794 * memory using malloc() directly).
796 * Pointers will be scanned assuming they are aligned.
798 * See_Also: removeRange(), addRoot(), removeRoot()
800 void addRange(void* ptr, size_t size)
802 this.root_ranges.append(RootRange(ptr, ptr + size));
806 * Remove a root pointer from the root set.
808 * ptr has to be previously registered using addRoot(), otherwise the
809 * results are undefined.
811 * See_Also: addRoot(), addRange(), removeRange()
813 void removeRoot(void* ptr)
815 this.root_pointers.remove(ptr);
819 * Remove a root range from the root set.
821 * ptr has to be previously registered using addRange(), otherwise the
822 * results are undefined.
824 * See_Also: addRange(), addRoot(), removeRoot()
826 void removeRange(void* ptr)
828 this.root_ranges.remove_if((ref RootRange range) {
829 return range.from is ptr;
835 // vim: set et sw=4 sts=4 :