.NET - the dark side

.NET - the dark side

Basic topics

why allocations

are problematic?

  • object allocations are done on the heap
  • when objects are released it creates holes
  • when fragmentation is to big - GC kicks in
  • it stops **all** the threads
  • it might be executed even few times a second

but we control where we new-ed objects

right?

boxing

the process of converting a value type to the type object or to any interface type implemented by this value type. When the CLR boxes a value type, it wraps the value inside a System.Object and stores it on the managed heap.

https://msdn.microsoft.com/en-us/library/yz2be5wk.aspx

Hidden pitfalls - boxing?

public void Debug(string logMessage)
{
    try
    {
        var logger = Logger;
        if (logger.IsDebugEnabled)
        {
            logger.DebugFormat(CultureInfo.InvariantCulture, logMessage);
        }
    }
    catch (Exception)
    {
        // We don't want logger making application to crash
    }
}
loggingService.Debug("StimmingService: " + 
        (currentStimulationControllerDecorator?.SupportedStimulationMode ?? StimulationMode.None) 
        + " stopped");

Can you spot the issue?

unnecessary boxing!

The fix?

void Debug<T>(string logMessage, T arg);
loggingService.Debug("StimmingService: {0} stopped", 
               currentStimulationControllerDecorator?.SupportedStimulationMode 
               ?? StimulationMode.None);
public void Debug<T>(string logMessage, T arg)
{
    try
    {
        var logger = Logger;
        if (logger.IsDebugEnabled)
        {
            logger.DebugFormat(CultureInfo.InvariantCulture, logMessage, arg);
        }
    }
    catch (Exception)
    {
        // We don't want logger making application to crash
    }
}

IL

Similar issue?

...
loggingService.Info($"Added new patient: {newPatient.FirstName} {newPatient.LastName}");
...

do you see it?

closure

In essence, a closure is a block of code which can be executed at a later time, but which maintains the environment in which it was first created - i.e. it can still use the local variables etc of the method which created it, even after that method has finished executing.

The general feature of closures is implemented in C# by anonymous methods and lambda expressions.

http://stackoverflow.com/questions/428617/what-are-closures-in-net#428624

Hidden pitfalls - closure?

int filter;
if (int.TryParse(Console.ReadLine(), out filter) == false) return;
var source = Enumerable.Range(1, 10000);
var filteredList = source.Where(i => Filter(i, filter));

Where is/are the allocation(s)?

Closure!

The fix?

int filter;
if (int.TryParse(Console.ReadLine(), out filter) == false) return;
var source = Enumerable.Range(0, 10000);
var enumerator = source.GetEnumerator();
while (enumerator.MoveNext())
{
    var current = enumerator.Current;
    if (current <= filter)
        Console.WriteLine(current);
}

old-fashioned enumerator

So how to live?

Do not start rewriting things!!!

Should we stop using LINQ?

NO

Should we be more aware that allocations might be the issuess?

Yes!

Consider no-allocations

for the critical path

ElectrodesService, FittingSessionService, DB loading client code

performance is a feature

Q & A?

.NET - the dark side

By Pawel Lukasik

.NET - the dark side

  • 282