GC interface. (#178)

This commit is contained in:
Nikolay Igotti
2017-01-13 12:03:38 +03:00
committed by GitHub
parent b1101ba43e
commit 239a573142
2 changed files with 117 additions and 9 deletions
+71 -7
View File
@@ -27,7 +27,7 @@ ContainerHeader ObjHeader::theStaticObjectsContainer = {
namespace {
#if USE_GC
// Collection threshold (collect after having so many elements in the
// Collection threshold default (collect after having so many elements in the
// release candidates set).
constexpr size_t kGcThreshold = 10000;
#endif
@@ -41,17 +41,23 @@ typedef std::vector<KRef*> KRefPtrList;
struct MemoryState {
// Current number of allocated containers.
int allocCount = 0;
#if TRACE_MEMORY
// List of all global objects addresses.
KRefPtrList* globalObjects;
// Set of all containers.
ContainerHeaderSet* containers;
#endif
#if USE_GC
// Set of references to release.
ContainerHeaderSet* toFree;
bool gcInProgress;
// How many GC suspend requests happened.
int gcSuspendCount;
// How many candidate elements in toFree shall trigger collection.
size_t gcThreshold;
// If collection is in progress.
bool gcInProgress;
#endif
};
@@ -189,7 +195,8 @@ void FreeContainer(ContainerHeader* header) {
#endif
header->ref_count_ = CONTAINER_TAG_INVALID;
#if USE_GC
memoryState->toFree->erase(header);
if (memoryState->toFree)
memoryState->toFree->erase(header);
#endif
// Now let's clean all object's fields in this container.
// TODO: this is gross hack, relying on the fact that we now only alloc
@@ -227,7 +234,8 @@ void FreeContainerNoRef(ContainerHeader* header) {
#endif
header->ref_count_ = CONTAINER_TAG_INVALID;
#if USE_GC
memoryState->toFree->erase(header);
if (memoryState->toFree)
memoryState->toFree->erase(header);
#endif
memoryState->allocCount--;
free(header);
@@ -322,9 +330,11 @@ inline void ReleaseRef(const ObjHeader* object) {
#if TRACE_MEMORY
fprintf(stderr, "%p is release candidate\n", object->container());
#endif
memoryState->toFree->insert(object->container());
if (memoryState->toFree->size() > memoryState->gcThreshold) {
GarbageCollect();
if (memoryState->toFree != nullptr) {
memoryState->toFree->insert(object->container());
if (memoryState->gcSuspendCount == 0 &&
memoryState->toFree->size() > memoryState->gcThreshold)
GarbageCollect();
}
#else // !USE_GC
Release(object->container());
@@ -357,6 +367,7 @@ void InitMemory() {
memoryState->toFree = new ContainerHeaderSet();
memoryState->gcInProgress = false;
memoryState->gcThreshold = kGcThreshold;
memoryState->gcSuspendCount = 0;
#endif
}
@@ -560,6 +571,7 @@ void ReleaseGlobalRefs(ObjHeader** start, int count) {
#if USE_GC
void GarbageCollect() {
RuntimeAssert(memoryState->toFree != nullptr, "GC must not be stopped");
RuntimeAssert(!memoryState->gcInProgress, "Recursive GC is disallowed");
memoryState->gcInProgress = true;
// Traverse inner pointers in the closure of release candidates, and
@@ -626,5 +638,57 @@ void Kotlin_konan_internal_GC_collect(KRef) {
#endif
}
void Kotlin_konan_internal_GC_suspend(KRef) {
#if USE_GC
memoryState->gcSuspendCount++;
#endif
}
void Kotlin_konan_internal_GC_resume(KRef) {
#if USE_GC
if (memoryState->gcSuspendCount > 0) {
memoryState->gcSuspendCount--;
if (memoryState->toFree != nullptr &&
memoryState->toFree->size() >= memoryState->gcThreshold) {
GarbageCollect();
}
}
#endif
}
void Kotlin_konan_internal_GC_stop(KRef) {
#if USE_GC
if (memoryState->toFree != nullptr) {
GarbageCollect();
delete memoryState->toFree;
memoryState->toFree = nullptr;
}
#endif
}
void Kotlin_konan_internal_GC_start(KRef) {
#if USE_GC
if (memoryState->toFree == nullptr) {
memoryState->toFree = new ContainerHeaderSet();
}
#endif
}
void Kotlin_konan_internal_GC_setThreshold(KRef, KInt value) {
#if USE_GC
if (value > 0) {
memoryState->gcThreshold = value;
}
#endif
}
KInt Kotlin_konan_internal_GC_getThreshold(KRef) {
#if USE_GC
return memoryState->gcThreshold;
#else
return -1;
#endif
}
} // extern "C"
+46 -2
View File
@@ -1,8 +1,52 @@
package konan.internal
// Garbage collector interface.
// TODO: more functions to come.
// Cycle garbage collector interface.
//
// Konan relies upon reference counting for object management, however it could
// not collect cyclical garbage, so we perform periodic garbage collection.
// This may slow down application, so this interface provides control over how
// garbage collector activates and runs.
// Garbage collector can be in one of the following states:
// * running
// * suspended (so cycle candidates are collected, but GC is not performed until resume)
// * stopped (all cyclical garbage is hopelessly lost)
// Immediately after startup GC is in running state.
// Depending on application needs it may select to suspend GC for certain phases of
// its lifetime, and resume it later on, or just completely turn it off, if GC pauses
// are less desirable than cyclical garbage leaks.
object GC {
// To force garbage collection immediately, unless collector is stopped
// with stop() operation. Even if GC is suspended, collect() still triggers collection.
@SymbolName("Kotlin_konan_internal_GC_collect")
external fun collect()
// Suspend garbage collection. Release candidates are still collected, but
// GC algorithm is not executed.
@SymbolName("Kotlin_konan_internal_GC_suspend")
external fun suspend()
// Resume garbage collection. Can potentially lead to GC immediately.
@SymbolName("Kotlin_konan_internal_GC_resume")
external fun resume()
// Stop garbage collection. Cyclical garbage is no longer collected.
@SymbolName("Kotlin_konan_internal_GC_stop")
external fun stop()
// Start garbage collection. Cyclical garbage produced while GC was stopped
// cannot be reclaimed, but all new garbage is collected.
@SymbolName("Kotlin_konan_internal_GC_start")
external fun start()
// GC threshold, controlling how frequenly GC is activated, and how much time GC
// takes. Bigger values lead to longer GC pauses, but less GCs.
var threshold: Int
get() = getThreshold()
set(value) = setThreshold(value)
@SymbolName("Kotlin_konan_internal_GC_getThreshold")
private external fun getThreshold(): Int
@SymbolName("Kotlin_konan_internal_GC_setThreshold")
private external fun setThreshold(value: Int)
}