Reclaiming memory

Since our microservice is about memory, let's create a simple routine to invoke the garbage collector, reclaim memory, and then report the results back to us. We will start by using our Start method to create a timer that will trigger every 60 seconds:

public bool Start([CanBeNull] HostControl host)
{
base.Start(host);
hc = host;
const double interval = 60000;
_timer = new Timer(interval);
_timer.Elapsed += OnTick;
Console.WriteLine(string.Intern("MemoryMicroService Started."));
return (true);
}

The method that our timer calls is the OnTick method. Each time this triggers, we will, in turn, call our ReclaimMemory function, which will invoke the garbage collector and reclaim memory. After it has completed this, it will report back memory both before and after collection, as well as the garbage collection count for each generation:

protected virtual void OnTick(object sender, ElapsedEventArgs e)
{
Console.WriteLine(string.Intern("Reclaiming Memory"));
ReclaimMemory();
}
/// <summary> Reclaim memory. </summary>
public static void ReclaimMemory()
{

Log the memory before the operation:

long mem2 = GC.GetTotalMemory(false);
Console.WriteLine(string.Intern("*** Memory ***"));
Console.WriteLine(string.Intern("tMemory before GC: ") + ToBytes(mem2));

Handle the large object heap compaction:

GCSettings.LargeObjectHeapCompactionMode = GCLargeObjectHeapCompactionMode.CompactOnce;
GC.Collect();
GC.WaitForPendingFinalizers();

Record the memory again:

long mem3 = GC.GetTotalMemory(false);
Console.WriteLine(string.Intern("tMemory after GC: ") + ToBytes(mem3));
Console.WriteLine("tApp memory being used: " + ToBytes(Environment.WorkingSet));
int gen1=0;
int gen2=0;
for (int x = 0; x < GC.MaxGeneration; x++)
{
if (x == 0)
gen1 = GC.CollectionCount(x);
else if (x == 1)
gen2 = GC.CollectionCount(x);
Console.WriteLine("ttGeneration " + (x) + " Collection Count: " + GC.CollectionCount(x));
}
const string category = ".NET CLR Memory";
const string counter = "% Time in GC";
string instance = Process.GetCurrentProcess().ProcessName;
float percent= 0.0F;
if (PerformanceCounterCategory.Exists(category) && PerformanceCounterCategory.CounterExists(counter, category) &&
PerformanceCounterCategory.InstanceExists(instance, category))
{
var gcPerf = new PerformanceCounter(category, counter, instance);
percent = gcPerf.NextValue();
string suffix = "%";
if (percent > 50.0)
{
suffix += " <- High Watermark Warning";
}
Console.WriteLine("ttTime Spent in GC: " + $"{percent:00.##}" + suffix);
}
Subscribe();

Publish our message:

PublishMessage(gen1, gen2, percent, ToBytes(mem2), ToBytes(mem3));
Console.WriteLine(string.Intern("*** Memory ***")); }
}

This is what our microservice looks like when it's running. You can see that the base class is sending out Heartbeat every five seconds. We did this, of course, so that we did not have to repeat the same code over and over again for each microservice. You can also see that the microservice reclaims memory and prints out exactly what it is doing every 60 seconds:

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset