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;