-2

Let's say I want to execute some command on many threads. I'd have this example code:

for (int i = 0; i < 5000; i++)
        {
            new Thread(() =>
            {
                while (true)
                {
                    string foo = "foo " + DateTime.Now.Ticks;

                    bool breakout = false;

                    for (int j = 0; j < random.Next(10, 100); j++)
                    {
                        string bar = "bar " + DateTime.Now.Ticks;
                        if (j == 5)
                        {
                            continue;
                        }
                        if (j == 8)
                        {
                            breakout = true;
                            break;
                        }
                    }

                    if (breakout)
                    {
                        continue;
                    }

                    string baz = "baz " + DateTime.Now.Ticks;
                }
            }).Start();
        }

This code example, creating 5K threads and setting some strings, leaks memory as far as I am concerned. As the code runs, the memory usage crawls higher and higher. Now, I think this is because I am setting variables and then abandoning them - is there a way I can continue/break without memory usage increasing more and more?

A. Hana
  • 7
  • 1
  • 1
    You're creating 5000 threads that never terminate. You are leaking memory. – Daniel Mann Oct 20 '17 at 21:03
  • 4
    Your title seems to "blame" break/continue. Do you not think it's more likely that "running 5000 threads that continuously create new strings" is the cause? (My guess is that your CPU is so heavily pegged that the GC isn't getting a chance to run.) – Jon Skeet Oct 20 '17 at 21:21
  • 1
    the `if (j == 5) continue;` part isn't needed since there is no other code that would run anyway - the loop will continue regardless. – Rufus L Oct 20 '17 at 21:26
  • You generating 5000 threads which are each producing between 11 and 101 22-character strings in a tight, never-ending loop. Perhaps you meant to have a `break` instead of a `continue` in the `if (breakout)` block? – Rufus L Oct 20 '17 at 21:31
  • @rufus-l Shouldn't the strings be discarded by GC though? – A. Hana Oct 20 '17 at 21:38
  • _"Shouldn't the strings be discarded by GC though?"_ -- yes, the GC can discard the `string` objects when they are no longer reachable. Each time the value of a local variable is replaced, that becomes the case for previously-created strings. But, unless you have a 5000-core machine, 5000 threads will create an enormous amount of contention for CPU, and the GC may not get a chance to run in a timely enough manner to quickly reclaim the memory. – Peter Duniho Oct 20 '17 at 22:32
  • Also, keep in mind that on the desktop, the GC is not very aggressive because there's lots of RAM (especially in a 64-bit process), and so .NET will allow memory usage to climb quite high before working hard to garbage-collect objects. – Peter Duniho Oct 20 '17 at 22:32

1 Answers1

-4

It's a classic issue with concatenating strings inside a loop with "+" characters. Instead use StringBuilder to combine strings when in a loop.

boateng
  • 910
  • 11
  • 21
  • There doesn't appear to be any issue with string concatenation (specifically) that would leak memory. All the strings are assigned only once, and they go out of scope on each iteration (and therefore become candidates for GC). Probably more likely that just the continuous creation of strings is filling memory before they can be collected. – Rufus L Oct 20 '17 at 21:19
  • Probably, but another question is if garbage collection time guaranteed or instantaneous – boateng Oct 20 '17 at 21:25
  • The infinite loop that concatenates a string with each iteration certainly will cause unbounded memory consumption. But switching to `StringBuilder` won't fix that. The "classic issue" you refer to involves _speed_ performance, not memory performance, because string concatenation isn't as efficient as using `StringBuilder`. Both ultimately result in the same _memory_ consumption. In any case, the OP isn't repeatedly concatenating the same string, and so wouldn't even run into the speed performance issue string concatenation causes. – Peter Duniho Oct 20 '17 at 22:28