-
Notifications
You must be signed in to change notification settings - Fork 0
/
MemoryUtils.cs
117 lines (94 loc) · 4.88 KB
/
MemoryUtils.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
using System.Diagnostics;
using System.Runtime;
using System.Runtime.InteropServices;
using Spectre.Console;
namespace EconomyBot;
public static class MemoryUtils {
public static void cleanGC() {
//Console.WriteLine("Forcing blocking GC collection and compacting of gen2 LOH and updating OS process working set size...");
var sw = Stopwatch.StartNew();
GCSettings.LargeObjectHeapCompactionMode = GCLargeObjectHeapCompactionMode.CompactOnce;
GC.Collect(generation: 2, GCCollectionMode.Aggressive, blocking: true, compacting: true);
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) {
WindowsMemoryUtility.ReleaseUnusedProcessWorkingSetMemory();
}
else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) {
LinuxMemoryUtility.ReleaseUnusedProcessWorkingSetMemoryWithMallocTrim();
LinuxMemoryUtility.ReleaseUnusedProcessWorkingSetMemoryWithMadvise_MADV_DONTNEED();
LinuxMemoryUtility.ReleaseUnusedProcessWorkingSetMemoryWithMadvise_MADV_PAGEOUT();
}
AnsiConsole.WriteLine($"Released memory in {sw.Elapsed.TotalMilliseconds} ms");
}
public class LinuxMemoryUtility {
[DllImport("libc", SetLastError = true)]
private static extern int madvise(IntPtr addr, UIntPtr length, int advice);
// https://github.com/torvalds/linux/blob/1a4e58cce84ee88129d5d49c064bd2852b481357/arch/alpha/include/uapi/asm/mman.h
private const int MADV_DONTNEED = 6;
private const int MADV_PAGEOUT = 21;
/// <summary>
/// https://linux.die.net/man/2/madvise
/// </summary>
public static void ReleaseUnusedProcessWorkingSetMemoryWithMadvise_MADV_DONTNEED() {
// https://linux.die.net/man/2/madvise
try {
var startMemoryAddress = Process.GetCurrentProcess().MainModule.BaseAddress;
var memoryLength = new UIntPtr((ulong)Process.GetCurrentProcess().WorkingSet64);
//Console.WriteLine($"Calling madvise with start: {startMemoryAddress} and length: {memoryLength}");
int result = madvise(startMemoryAddress, memoryLength, MADV_DONTNEED);
//Console.WriteLine($"Result: {result}");
// On success madvise() returns zero. On error, it returns -1 and errno is set appropriately.
//if (result != 0) {
// Console.WriteLine($"madvise errno: {Marshal.GetLastSystemError()}");
//}
}
catch (Exception exc) {
AnsiConsole.WriteLine(exc.ToString());
}
}
/// <summary>
/// https://linux.die.net/man/2/madvise
/// </summary>
public static void ReleaseUnusedProcessWorkingSetMemoryWithMadvise_MADV_PAGEOUT() {
try {
var startMemoryAddress = Process.GetCurrentProcess().MainModule.BaseAddress;
var memoryLength = new UIntPtr((ulong)Process.GetCurrentProcess().WorkingSet64);
//Console.WriteLine($"Calling madvise with start: {startMemoryAddress} and length: {memoryLength}");
int result = madvise(startMemoryAddress, memoryLength, MADV_PAGEOUT);
//Console.WriteLine($"Result: {result}");
// On success madvise() returns zero. On error, it returns -1 and errno is set appropriately.
//if (result != 0) {
// Console.WriteLine($"madvise errno: {Marshal.GetLastSystemError()}");
//}
}
catch (Exception exc) {
AnsiConsole.WriteLine(exc.ToString());
}
}
[DllImport("libc", SetLastError = true)]
private static extern int malloc_trim(uint pad);
public static void ReleaseUnusedProcessWorkingSetMemoryWithMallocTrim() {
// https://man7.org/linux/man-pages/man3/malloc_trim.3.html
try {
//Console.WriteLine($"Calling malloc_trim(0)");
int result = malloc_trim(0);
//Console.WriteLine($"Result: {result}");
// The malloc_trim() function returns 1 if memory was actually
// released back to the system, or 0 if it was not possible to
// release any memory.
if (result != 1) {
AnsiConsole.WriteLine($"malloc_trim errno: {Marshal.GetLastSystemError()}");
}
}
catch (Exception exc) {
AnsiConsole.WriteLine(exc.ToString());
}
}
}
public class WindowsMemoryUtility {
[DllImport("kernel32.dll", SetLastError = true)]
static extern bool SetProcessWorkingSetSize(IntPtr proc, int minSize, int maxSize);
public static void ReleaseUnusedProcessWorkingSetMemory() {
SetProcessWorkingSetSize(Process.GetCurrentProcess().Handle, -1, -1);
}
}
}