Quick reference guide and runtime errors.
This commit is contained in:
parent
87dc0fef2d
commit
ad29cc5ee5
5 changed files with 89 additions and 52 deletions
|
|
@ -1,47 +0,0 @@
|
||||||
## Heap Documentation
|
|
||||||
|
|
||||||
### Algorithm notes
|
|
||||||
|
|
||||||
void mark_test(vector<Chunk *> worklist) {
|
|
||||||
while (worklist.size() > 0) {
|
|
||||||
Chunk *ref = worklist.pop_back();
|
|
||||||
Chunk *child = (Chunk*) *ref;
|
|
||||||
if (child != NULL && !child->marked) {
|
|
||||||
child->marked = true;
|
|
||||||
worklist.push_back(child);
|
|
||||||
mark_test(worklist);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void mark_from_roots(uintptr_t *start, const uintptr_t *end) {
|
|
||||||
vector<Chunk *> worklist;
|
|
||||||
for (;start > end; start--) {
|
|
||||||
Chunk *ref = *start;
|
|
||||||
if (ref != NULL && !ref->marked) {
|
|
||||||
ref->marked = true;
|
|
||||||
worklist.push_back(ref);
|
|
||||||
mark_test(worklist);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Alternative marking, pseudocode
|
|
||||||
|
|
||||||
mark_from_roots():
|
|
||||||
worklist <- empty
|
|
||||||
for fld in Roots
|
|
||||||
ref <- *fld
|
|
||||||
if ref ≠ null && !marked(ref)
|
|
||||||
set_marked(ref)
|
|
||||||
worklist.add(ref)
|
|
||||||
mark()
|
|
||||||
|
|
||||||
mark():
|
|
||||||
while size(worklist) > 0
|
|
||||||
ref <- remove_first(worklist)
|
|
||||||
for fld in Pointers(ref)
|
|
||||||
child <- *fld
|
|
||||||
if child ≠ null && !marked(child)
|
|
||||||
set_marked(child)
|
|
||||||
worklist.add(child)
|
|
||||||
83
src/GC/docs/ref-guide.md
Normal file
83
src/GC/docs/ref-guide.md
Normal file
|
|
@ -0,0 +1,83 @@
|
||||||
|
# GC library - reference guide
|
||||||
|
|
||||||
|
The Heap class is the core of the library and contains all necessary
|
||||||
|
functions for using the library. This class exposes four public functions
|
||||||
|
which are `init`, `dispose`, `alloc`, and `set_profiler`.
|
||||||
|
|
||||||
|
To use the library, simply include it as `#include "heap.hpp"` and link
|
||||||
|
it during compilation. Or you can compile it to a static library using
|
||||||
|
the target `make static_lib` which compiles everything to an .a file.
|
||||||
|
It can also be compiled to a shared library if necessary with the target
|
||||||
|
`make shared_lib` which produces an .so file.
|
||||||
|
|
||||||
|
## Quick guide
|
||||||
|
1. If you want a profiler, call `Heap::set_profiler(true)`. Otherwise this can be skipped.
|
||||||
|
2. Call `Heap::init()` to initialize the heap before using `alloc` (**crucial**).
|
||||||
|
3. Use `Heap::alloc()` as you want.
|
||||||
|
4. At program exit, call `Heap::dispose()` to free up all the memory used.
|
||||||
|
|
||||||
|
## Functions
|
||||||
|
|
||||||
|
### Heap::init()
|
||||||
|
When using the library, the user has to, at the start of the program,
|
||||||
|
call the `void init()` function, which initiates the Heap singleton
|
||||||
|
and the class member `m_stack_top`. **It is crucial** that this
|
||||||
|
functions is called from the `main` function of the end program,
|
||||||
|
as `init` uses the intrinsic function `__builtin_frame_address`
|
||||||
|
to find the address of the **first** stack frame of the end program.
|
||||||
|
If the function **is not** called from the `main` function
|
||||||
|
of the end program, it is not guaranteed that the garbage collector
|
||||||
|
will collect all objects.
|
||||||
|
|
||||||
|
The intrinsic function used is technically unsafe for this use,
|
||||||
|
but during testing it has only shown to segfault for values greater
|
||||||
|
than the one used in `init`. If you run into a segfault, please
|
||||||
|
contact the developers.
|
||||||
|
|
||||||
|
|
||||||
|
### Heap::set_profiler(bool mode)
|
||||||
|
This function is used to enable or disable the profiler connected
|
||||||
|
to the Heap. The profiler is primarily used for testing, but can
|
||||||
|
also be used in general to keep track of the programs history.
|
||||||
|
|
||||||
|
This function takes a single boolean as an argument to represent
|
||||||
|
the state of the profiler. `true` means that the profiler is enabled
|
||||||
|
and `false` means that the profiler is disabled. This function
|
||||||
|
can theoretically be called at any time during program execution,
|
||||||
|
but it's probably a bad idea. It is recommended to call this function
|
||||||
|
before the call to `init` or at least at before the first call to
|
||||||
|
`alloc`.
|
||||||
|
|
||||||
|
### Heap::alloc(size_t size)
|
||||||
|
The probably most important function in this library. This function
|
||||||
|
is called to request memory from the "heap". `alloc` takes a single
|
||||||
|
argument which is a `size_t` (unsigned long) to represent the amount
|
||||||
|
of bytes to allocate on the heap. The allocation is C-style, meaning
|
||||||
|
that alloc returns a `void` pointer similar to `malloc`, which
|
||||||
|
is then supposed to be cast by the user to a proper pointer. When
|
||||||
|
`alloc` is called and there is already not enough memory left on
|
||||||
|
the heap to accommodate the request, a collection is triggered
|
||||||
|
to free up memory for the allocation. Hence the user does not
|
||||||
|
need to make their own calls to `free` or manually free up memory.
|
||||||
|
|
||||||
|
`alloc` can also return a null pointer, if the user requests to
|
||||||
|
allocate 0 bytes. This is not recommended.
|
||||||
|
|
||||||
|
`alloc` can also throw runtime errors in two cases. The first one
|
||||||
|
is of there is not enough memory on the heap available after
|
||||||
|
a collection, which in case the allocation cannot complete.
|
||||||
|
The second case is during a collection, where the function
|
||||||
|
`collect` throws a runtime error if the heap is not already
|
||||||
|
initialized by a call to `init`. Calls to `alloc` can technically
|
||||||
|
take place without properly initializing the heap, but this is
|
||||||
|
not recommended.
|
||||||
|
|
||||||
|
### Heap::dispose()
|
||||||
|
This function is used to dispose the heap at the program exit.
|
||||||
|
If the profiler is enabled, it is also disposed from a call
|
||||||
|
to `dispose`. When the profiler is disposed, a log file is
|
||||||
|
dumped containing the events on the heap. If the profiler
|
||||||
|
is disabled, nothing happens to the profiler during `dispose`.
|
||||||
|
After the profiler is disposed, the heap is deleted which
|
||||||
|
frees up all the memory used and deletes (hopefully) all
|
||||||
|
the remaining objects in memory.
|
||||||
|
|
@ -123,6 +123,7 @@ namespace GC
|
||||||
static void init();
|
static void init();
|
||||||
static void dispose();
|
static void dispose();
|
||||||
static void *alloc(size_t size);
|
static void *alloc(size_t size);
|
||||||
|
void set_profiler(bool mode);
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
static Heap *debug_the()
|
static Heap *debug_the()
|
||||||
|
|
@ -136,7 +137,6 @@ namespace GC
|
||||||
void check_init(); // print dummy things
|
void check_init(); // print dummy things
|
||||||
void print_contents(); // print dummy things
|
void print_contents(); // print dummy things
|
||||||
void print_allocated_chunks(Heap *heap); // print the contents in m_allocated_chunks
|
void print_allocated_chunks(Heap *heap); // print the contents in m_allocated_chunks
|
||||||
void set_profiler(bool mode);
|
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
@ -4,6 +4,7 @@
|
||||||
#include <execinfo.h>
|
#include <execinfo.h>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <setjmp.h>
|
#include <setjmp.h>
|
||||||
|
#include <stdexcept>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
|
@ -70,7 +71,7 @@ namespace GC
|
||||||
{
|
{
|
||||||
heap->collect();
|
heap->collect();
|
||||||
// If memory is not enough after collect, crash with OOM error
|
// If memory is not enough after collect, crash with OOM error
|
||||||
assert(heap->m_size + size <= HEAP_SIZE && "Heap: Out Of Memory");
|
throw std::runtime_error(std::string("Error: Heap out of memory"));
|
||||||
}
|
}
|
||||||
|
|
||||||
// If a chunk was recycled, return the old chunk address
|
// If a chunk was recycled, return the old chunk address
|
||||||
|
|
@ -164,7 +165,7 @@ namespace GC
|
||||||
auto stack_bottom = reinterpret_cast<uintptr_t *>(__builtin_frame_address(0));
|
auto stack_bottom = reinterpret_cast<uintptr_t *>(__builtin_frame_address(0));
|
||||||
|
|
||||||
if (heap->m_stack_top == nullptr)
|
if (heap->m_stack_top == nullptr)
|
||||||
assert(false && "Heap is not initialized, read the docs!");
|
throw std::runtime_error(std::string("Error: Heap is not initialized, read the docs!"));
|
||||||
|
|
||||||
uintptr_t *stack_top = heap->m_stack_top;
|
uintptr_t *stack_top = heap->m_stack_top;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,6 @@
|
||||||
Deliver to samuel
|
Deliver to samuel
|
||||||
|
|
||||||
## GC TODO:
|
## GC TODO:
|
||||||
- Code cleanup
|
|
||||||
- Dokumentera
|
- Dokumentera
|
||||||
- Dokumentera alla filer och funktioner
|
- Dokumentera alla filer och funktioner
|
||||||
- Skriva reference guide för Samuel
|
- Skriva reference guide för Samuel
|
||||||
|
|
@ -12,3 +11,4 @@ Deliver to samuel
|
||||||
|
|
||||||
## Tests TODO
|
## Tests TODO
|
||||||
- Write complex datastructures for tests with larger programs
|
- Write complex datastructures for tests with larger programs
|
||||||
|
- Testa `__builtin_frame_address` mer specifikt för att se om första stack framen skannas
|
||||||
Loading…
Add table
Add a link
Reference in a new issue