1 /** 2 Copyright: Copyright (c) 2020, Joakim Brännström. All rights reserved. 3 License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0) 4 Author: Joakim Brännström (joakim.brannstrom@gmx.com) 5 6 Trim the heap size by periodically force the GC to collect unused memory, free 7 it and then tell malloc to further free it back to the OS. 8 */ 9 module my.gc.memfree; 10 11 import std.concurrency : send, spawn, receiveTimeout, Tid; 12 13 import my.gc.refc; 14 15 /// Returns: a started instance of MemFree. 16 RefCounted!MemFree memFree() @safe { 17 MemFree inst; 18 inst.start; 19 return RefCounted!MemFree(inst); 20 } 21 22 /** Reduces the used memory by the GC and free the heap to the OS. 23 * 24 * To avoid calling this too often the struct have a timer to ensure it is 25 * callled at most ones every minute. 26 * 27 * TODO: maybe add functionality to call it more often when above e.g. 50% memory usage? 28 */ 29 struct MemFree { 30 private { 31 bool isRunning; 32 Tid bg; 33 } 34 35 ~this() @trusted { 36 if (!isRunning) 37 return; 38 39 scope (exit) 40 isRunning = false; 41 send(bg, Msg.stop); 42 } 43 44 /** Start a background thread to do the work. 45 * 46 * It terminates when the destructor is called. 47 */ 48 void start() @trusted { 49 bg = spawn(&tick); 50 isRunning = true; 51 } 52 53 } 54 55 private: 56 57 enum Msg { 58 stop, 59 } 60 61 void tick() nothrow { 62 import core.time : dur; 63 import core.memory : GC; 64 65 const tickInterval = 1.dur!"minutes"; 66 67 bool running = true; 68 while (running) { 69 try { 70 receiveTimeout(tickInterval, (Msg x) { running = false; }); 71 } catch (Exception e) { 72 running = false; 73 } 74 75 GC.collect; 76 GC.minimize; 77 malloc_trim(0); 78 } 79 } 80 81 // malloc_trim - release free memory from the heap 82 extern (C) int malloc_trim(size_t pad) nothrow @system;