Skip to content

Instantly share code, notes, and snippets.

@FeepingCreature
Created June 20, 2023 05:43
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save FeepingCreature/3baf6bd62dc64441fe73f46e3df9b482 to your computer and use it in GitHub Desktop.
Save FeepingCreature/3baf6bd62dc64441fe73f46e3df9b482 to your computer and use it in GitHub Desktop.
module test;
import core.memory : GC;
import core.sync.semaphore;
import core.sys.linux.sys.mman : MADV_DONTNEED, madvise;
import core.thread;
import std;
enum keys = [
"foo", "bar", "baz", "whee",
"foo1", "foo2", "foo3", "foo4", "foo5", "foo6", "foo7", "foo8",
"bar1", "bar2", "bar3", "bar4", "bar5", "bar6", "bar7", "bar8",
"baz1", "baz2", "baz3", "baz4", "baz5", "baz6", "baz7", "baz8"];
void spamGC(Semaphore sema) {
void recursionTest(int depth) {
if (depth < 1000) {
recursionTest(depth + 1);
if (depth % 300 == 0)
recursionTest(depth + 1);
}
string[string] assocArray;
static foreach (a; keys)
{
assocArray[a] = a;
}
assocArray.clear;
assocArray = null;
}
void pushTest() {
import core.stdc.stdlib : alloca;
alloca(10_000);
recursionTest(0);
}
void cleanerTest() {
auto cleaner = new StackCleaner;
cleaner.run({
recursionTest(0);
});
}
// recursionTest(0);
// pushTest;
cleanerTest;
sema.notify;
Thread.sleep(3600.seconds);
}
void main() {
Thread[] threads;
auto sema = new Semaphore(0);
enum threadCount = 100;
threadCount.iota.each!((_) {
auto thread = new Thread({ spamGC(sema); });
thread.start;
threads ~= thread;
});
threadCount.iota.each!((i) {
sema.wait;
});
// this clears the leak up!
// threads.each!((thread) { thread.join; });
writefln!"Done.";
GC.collect;
GC.minimize;
writefln!"Collected.";
// Now look at residential memory for the process.
Thread.sleep(3600.seconds);
}
class StackCleaner
{
private Fiber fiber;
private void delegate() action;
private bool done;
private void* stackBottom;
enum stackSize = 8 * 1024 * 1024;
public this()
{
this.done = false;
this.fiber = new Fiber(&execute, stackSize);
}
public void run(void delegate() action)
{
scope (exit)
{
void* fiberStackLowEnd = this.stackBottom - stackSize;
const result = madvise(fiberStackLowEnd, stackSize, MADV_DONTNEED);
errnoEnforce(result == 0, "madvise failed");
// And re-setup the context.
this.fiber.reset;
}
this.action = action;
this.done = false;
while (!this.done)
{
this.fiber.call;
}
}
private void execute()
{
this.stackBottom = thread_stackBottom;
this.action();
this.done = true;
}
}
private extern (C) void* thread_stackBottom() nothrow @nogc;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment