views:

88

answers:

4

My C# (.NET 2.0) application has a StringBuilder variable with a capacity of 2.5MB. Obviously, I do not want to copy such a large buffer to a larger buffer space every time it fills. By that point, there is so much data in the buffer anyways, removing the older data is a viable option. Can anyone see any obvious problems with how I'm doing this (i.e. am I introducing more performance problems than I'm solving), or does it look okay?

  tText_c = new StringBuilder(2500000, 2500000);

  private void AppendToText(string text)
  {
     if (tText_c.Length * 100 / tText_c.Capacity > 95)
     {
        tText_c.Remove(0, tText_c.Length / 2);
     }

     tText_c.Append(text);
  }

EDIT: Additional information:

In this application new data is received very rapidly (on the order of milliseconds) through a serial connection. I don't want to populate the multiline textbox with this new information so frequently because that kills the performance of the application, so I'm saving it to a StringBuilder. Every so often, the application copies the contents of the StringBuilder to the textbox and wipes out the StringBuilder contents.

+1  A: 

How are you actually using this StringBuilder? The fact that you're removing stuff from it suggests you're really using it as a sort of buffer.

Note that calling Remove like this will already be copying the second half of the buffer into the first, so you're still doing a lot of copying.

Instead of using a StringBuilder, could you use a circular buffer of strings? That would make it almost free to discard old data and replace it with new strings. Do you need to do anything with the builder other than appending whole strings and occasionally (presumably) converting the whole thing into a single string?

Jon Skeet
The `StringBuilder` is being used to buffer ASCII text to be later copied to a multiline text box. The text box does not always need to be updated (hundreds, if not thousands, of times a second) and redrawn, which is why I'm appending text into a `StringBuilder`.
Jim Fell
@Jim Fell: Okay, it sounds like a circular buffer of strings would indeed be a better way to go then.
Jon Skeet
Or maybe even just a simple queue
Joel Coehoorn
@Joel: If the idea is to just ditch data if there's too much, a circular buffer allows that to be done more easily than a queue.
Jon Skeet
@Jon: Thanks for the idea. I started implementing a circular buffer, but as I got into it I realized that I'd be doing just as much copying, if not more, than with the implementation I currently have.
Jim Fell
@Jim: That's very unlikely - you'd only be copying string *references* rather than the *contents* of strings, up until the point at which you needed to write to the textbox. `StringBuilder.Append` will copy all of the string *data* - and then do so again when you call `ToString`. Moreover, the point of a circular buffer is that you never have to copy a whole block of data just to add or remove an item - you just update the indexes, effectively. Compare this with removing a large chunk of a StringBuilder...
Jon Skeet
A: 

Do you maybe want a stringstream or memorystream instead? You can write into the stream and read from it as needed.

I can see all kinds of problems with letting your StringBuilder grow large like that, not the least of which is that it's gonna sit on the large object heap.

Joel Coehoorn
Joel, can you provite (or link to) an example of `StringStream`? I found `MemoryStream`, but as near as I could tell, it allows only fixed buffer sizes.
Jim Fell
@Jim - I was confusing `System.IO.StringReader` with my C++ days. As for memorystream, it does have a fixed buffer, but the idea is that because it's a stream the buffer is cleared as your read from it.
Joel Coehoorn
+1  A: 

"...is being used to buffer ASCII text to be later copied to a multiline text box.."

Your textbox is going to have a seizure when you get past ~200kb...it won't fail...but its performance will drop like a stone. A control that uses a string collection of some sort might be a better idea...maybe a ListBox ?...pseudo example :

public void AddText(string text){
  ListBox.items.add(text);
  if(ListBox.items.count > 4096){
    ListBox.items[0].remove();
  } 
}

"..need to be updated (hundreds, if not thousands, of times a second) and redrawn.."

Your Ui update rate is not reasonably going to better than ~50hz...might have an effect on your buffer structures.

Rusty
Rusty, you raise some good points. Right now, for the sake of (my) time, I'm thinking of going with my original approach, except the buffer would be 90%-95% cleared, so that only 5%-10% would need to be copied.
Jim Fell
A: 

I was able to resolve the performance problems I was having by allocating a buffer large enough to store enough text for a single pass through the application sequence (and then some). Every time the sequence is (re)started, the buffers are cleared.

Jim Fell