diff --git a/changelog/gc_cleanup.dd b/changelog/gc_cleanup.dd new file mode 100644 index 0000000000..82277817f3 --- /dev/null +++ b/changelog/gc_cleanup.dd @@ -0,0 +1,26 @@ +GC cleanup can now be configured as a DRT GC option + +The default cleanup method for the GC is to unconditionally run a +collection before runtime termination to finalize objects +that are still alive and hold resources that affect system state outside +the current process. This combines the worst of possible alternatives: +it can cause a considerable delay and does not guarantee finalization +of all objects as roots might still exist. + +The cleanup behaviour can now be configured by a DRT option to the +$(LINK2 $(ROOT_DIR)spec/garbage.html, GC configuration), +e.g. by passing `--DRT-gcopt=cleanup:none` on the command +line. Three options are provided: + +$(UL + $(LI collect: run a collection (the default for backward compatibility)) + $(LI none: do nothing) + $(LI finalize: all live objects are finalized unconditionally) +) + +As usual, you can also embed the configuration into the application by +redefining `rt_options`, e.g. + +------- +extern(C) __gshared string[] rt_options = [ "gcopt=cleanup:none" ]; +------- diff --git a/src/gc/config.d b/src/gc/config.d index 1a3631bd88..31c1020864 100644 --- a/src/gc/config.d +++ b/src/gc/config.d @@ -23,6 +23,7 @@ struct Config size_t maxPoolSize = 64; // maximum pool size (MB) size_t incPoolSize = 3; // pool size increment (MB) float heapSizeFactor = 2.0; // heap size to used memory ratio + string cleanup = "collect"; // select gc cleanup method none|collect|finalize @nogc nothrow: @@ -43,6 +44,7 @@ struct Config maxPoolSize:N - maximum pool size in MB (%lld) incPoolSize:N - pool size increment MB (%lld) heapSizeFactor:N - targeted heap size to used memory ratio (%g) + cleanup:none|collect|finalize - how to treat live objects when terminating (collect) "; printf(s.ptr, disable, profile, cast(long)initReserve, cast(long)minPoolSize, cast(long)maxPoolSize, cast(long)incPoolSize, heapSizeFactor); diff --git a/src/gc/proxy.d b/src/gc/proxy.d index b6a9595ef8..d66c6e92a1 100644 --- a/src/gc/proxy.d +++ b/src/gc/proxy.d @@ -79,20 +79,35 @@ extern (C) void gc_term() { - // NOTE: There may be daemons threads still running when this routine is - // called. If so, cleaning memory out from under then is a good - // way to make them crash horribly. This probably doesn't matter - // much since the app is supposed to be shutting down anyway, but - // I'm disabling cleanup for now until I can think about it some - // more. - // - // NOTE: Due to popular demand, this has been re-enabled. It still has - // the problems mentioned above though, so I guess we'll see. - if (isInstanceInit) { - instance.collectNoStack(); // not really a 'collect all' -- still scans - // static data area, roots, and ranges. + switch (config.cleanup) + { + default: + import core.stdc.stdio : fprintf, stderr; + fprintf(stderr, "Unknown GC cleanup method, please recheck ('%.*s').\n", + cast(int)config.cleanup.length, config.cleanup.ptr); + break; + case "none": + break; + case "collect": + // NOTE: There may be daemons threads still running when this routine is + // called. If so, cleaning memory out from under then is a good + // way to make them crash horribly. This probably doesn't matter + // much since the app is supposed to be shutting down anyway, but + // I'm disabling cleanup for now until I can think about it some + // more. + // + // NOTE: Due to popular demand, this has been re-enabled. It still has + // the problems mentioned above though, so I guess we'll see. + + instance.collectNoStack(); // not really a 'collect all' -- still scans + // static data area, roots, and ranges. + break; + case "finalize": + instance.runFinalizers((cast(ubyte*)null)[0 .. size_t.max]); + break; + } ManualGC.finalize(instance); ConservativeGC.finalize(instance);