How to avoid GC when working with strings

I would like just to ask you if you have some suggestion how to avoid garbage when we manipulate with strings.
I know NET(NETMF) is very powerful and comfortable regarding string manipulations but behind the scene there is potential overhead because GC must collect all of these immutable strings.

Let say we must refresh LCD character display regularly every 200msec through UART with e.g. time and technology data. So we must build every 200msec. some strings.

I know there exists StringBuilder which is more efficient than “standard” string operations but also StringBuilder generates “food” for GC at least according these articles:

[url]http://www.gavpugh.com/2010/04/01/xnac-avoiding-garbage-when-working-with-stringbuilder/[/url]
and
[url]http://www.gavpugh.com/2010/03/23/xnac-stringbuilder-to-string-with-no-garbage/[/url]

Here is an example for creation string for one 20 characters LCD line with StringBuilder:



StringBuilder timeStampString = new StringBuilder(20, 35); // class member 
DateTime timeStamp; // class member 
int refreshTimer = 0;
.....

override public void RefreshScreen()
    {
      refreshTimer++;
      if ((refreshTimer % 2) == 0)
      {
        timeStamp = RealTimeClock.GetDateTime();

        timeStampString.Clear();
        timeStampString.Append(timeStamp.ToString("dd.MM.yyyy HH:mm:ss"));

        SerialCharacterLCD.Instance.Write(timeStampString.ToString());

      }
    }


According mentioned articles also StringBuilder.ToString() method also generates immutable string in heap so GC has to work latter on.
There is specified some trick using reflection in those articles but it is little bit overkill I suppose and also did not work for me(maybe I made something wrong when tried…).

I am quite new in NET(NETMF) so I am asking if there is any proven solution to minimize GC impact especially during frequent String manipulations?

You could try to write the characters directly from the StringBuilder internal buffer to the LCD.
If the “SerialCharacterLCD.Instance.Write()” method is a managed method, then you could just iterate over the StringBuilder buffer and write each character to the LCD. If the Write() method is a native method then this would mean a huge performance loss I guess.

Here is implementation of SerialCharacterLCD.Instance.Write():


public void Write(string text)
    {
      serialPort.Send(text);
    }
.....

public void Send(string text)
    {
        System.Text.UTF8Encoding encoder = new System.Text.UTF8Encoding();
        byte[] bytesToSend = encoder.GetBytes(text);
        serialPort.Write(bytesToSend, 0, bytesToSend.Length);
    }

A couple of suggestions. First, stop 'new’ing an encoder for every call - that’s just churning up heap space. Second, use a single pre-allocated class-instance or static buffer and use this overload for the decoder:



That overload writes into a pre-allocated buffer rather than creating a new array.  Using pre-allocated buffers is one of your best defenses against churning the heap and triggering GC passes.

If you are using static or pre-allocated buffers, and multiple threads, then be sure to make your code thread-safe with lock() or the synchronization method attribute so that two parallel calls to your method don't try to use the buffer at the same time.

Icing on the cake, this overload does not throw exceptions when the initial string contains non-UTF8 compliant chars :dance:
Pretty useful when you have to deal with chinese firmwares…

Also, when you have known idle times, you could run GC by yourself to make interruptions less likely.