-
-
Notifications
You must be signed in to change notification settings - Fork 416
Refactor GC #1081
Refactor GC #1081
Conversation
It's a lot more readable this way, but obviously there's still a bug somewhere. One functional change is that the old version still did a collection if the GC is disabled but the OS does not return more memory. Regarding style: please don't put |
Yes, it did so, but I thought that was rather a bug. |
6e02921
to
b4f89c2
Compare
I sometimes use GC.disable to prevent crashes when using libraries that allocate in destructors, so it really does look like a bug. |
And it doesn't seem to be the reason for the test failure. I'd also say disable should be disable. |
95d38f9
to
7fa750e
Compare
There is also the use case "I want my program fast for this section of code but I don't want it to fail arbitrarily" where the current behaviour makes sense. Maybe it should be some multi-level option? |
Not if I |
7fa750e
to
6ed1ea9
Compare
OK, found the bug. |
This pull contains one semantic change, namely disable really means disable and we never collect. |
I think we should be more conservative here. Hitting the address space limit is not so uncommon for 32-bit processes, especially if you don't have the /LARGEADDRESSAWARE bit specified. |
6ed1ea9
to
58bf850
Compare
Thanks for being so persistent about this, a simple look on the docs would have solved the question. |
I wasn't aware it's in the docs. LGTM, though I'll probably hate it for the conflicts it will cause for other changes to the GC. ;-) |
Auto-merge toggled on |
True, but the bad/fragile code is one of the biggest hurdles to actually improve the GC. BTW, I already tried to use SIMD in the marking code with pretty bad results. Either the benchmark was completely mem-bandwidth limited (SIMD just adds more instructions) or it was CPU limited (slist) and suffered from the increased complexity. It should be possible though to turn almost the whole mark function into SIMD code, thereby saving somewhat on instruction count. That will only return a marginal interest. Ultimately we have to figure out how to do incremental collections, it really hurts having to mark 500MB to collect 10MB. I found an extremely interesting paper (Connectivity-Based Garbage Collection) that achieves incremental collection by using type information rather than age of allocations and it doesn't require barriers or compacting. |
The new growth strategy really looks promising, same graph as above, much less time spend collecting. |
I agree, this definitely is a pain to rebase upon, especially with the change to the location of setBits, as I get to do the rebase and attempt to keep it with the design it had at the time... (refering to the struct destructors PR) |
Sorry for that, but there are many more changes to come, because the code base is crap. |
@MartinNowak can you post how you generate these graph ? I'd be interested to generate them for SDC if that is possible. |
I patched the GC using this, then fed the output into diff --git a/src/gc/gc.d b/src/gc/gc.d
index 4ce4ccf..50768d2 100644
--- a/src/gc/gc.d
+++ b/src/gc/gc.d
@@ -2401,6 +2401,8 @@ struct Gcx
{
MonoTime start, stop, begin;
+ printStats();
+
if (GC.config.profile)
{
begin = start = currTime;
@@ -2454,16 +2456,34 @@ struct Gcx
{
stop = currTime;
recoverTime += (stop - start);
- ++numCollections;
}
running = false; // only clear on success
+ printStats();
+ ++numCollections;
updateCollectThresholds();
return freedLargePages + freedSmallPages;
}
+ private void printStats() nothrow
+ {
+ size_t heap, free;
+ foreach (p; pooltable[0 .. npools])
+ {
+ heap += p.npages * PAGESIZE;
+ free += p.freepages * PAGESIZE;
+ }
+
+ foreach (n; 0 .. B_PAGE)
+ for (auto el = bucket[n]; el; el = el.next)
+ free += binsize[n];
+
+ assert(free <= heap);
+ printf("%zu,%zu,%zu\n", numCollections, heap, heap - free);
+ }
+
/**
* Returns true if the addr lies within a marked block.
* |
simplify heap grow code