19

For example:

            for (i = 0; i < 100; i++)
            {
               string myvar = "";
                // Some logic
            }

Do it make performace or memory leak?

Why i do this, because i don't want "myvar" accessible outside the for..loop.

It is any performance monitor, i can compare the execute time between two snippet or whole program ?

thanks you.

Cheung
  • 15,293
  • 19
  • 63
  • 93
  • 1
    There are no memory leaks in C#. only cyclic references which you won't get with a string. – Daniel Oct 25 '11 at 02:40
  • 2
    @Dani: There is less chance of memory leaks in .NET, but they absolutely can occur. – Scott Dorman Oct 25 '11 at 02:48
  • @ScottDorman: have an example? – Daniel Oct 25 '11 at 02:49
  • 2
    @Dani: Eat your heart out: http://msdn.microsoft.com/en-us/magazine/cc163491.aspx#S5 – StriplingWarrior Oct 25 '11 at 03:32
  • 1
    @StriplingWarrior: this is just because of retaining a reference for unneeded object. yes, you can push every object you ever use to a global `Stack` and yell "C# IS LEAKY!!!" but that's just damn stupid, and can't be solved with any language. – Daniel Oct 25 '11 at 03:44
  • @Dani: Nobody's yelling about C# being leaky. As you say, there are some problems that can't be solved in any framework or language that allows you to allocate memory. So it's a little silly to say there "are no memory leaks in C#." The memory leaks are easier to avoid in managed code, but they can still happen, and often do in complex projects. – StriplingWarrior Oct 25 '11 at 03:54
  • @StriplingWarrior: What I generally meant is that the easiest design will not come strictly with memory leaks, as opposed to other languages (most notably, C). – Daniel Oct 25 '11 at 04:00
  • @Dani: That is true. It is worth noting, though, that the C equivalent of the given code sample would not cause a memory leak either, since no `new` memory is being allocated. – StriplingWarrior Oct 25 '11 at 04:06

8 Answers8

19

No, variables are purely for the programmer's convenience. It doesn't matter where you declare them. See my answer to this duplicate question for more details.

Community
  • 1
  • 1
StriplingWarrior
  • 151,543
  • 27
  • 246
  • 315
  • Generally, you shouldn't be doing string manipulation inside of a loop due to string immutability since you'll be creating a new string each time. – Scott Dorman Oct 25 '11 at 02:39
  • 1
    @ScottDorman: Read the question, friend. He's not asking about doing string manipulation. He's asking about declaring a variable. – StriplingWarrior Oct 25 '11 at 02:42
  • It does matter where he declares them, while although C# doesn't have RAII, it has simulated one by its garbage collector scanning the stack. while a variable is in scope it won't be collected, so if you put it nested deep it might be collected and if not nested it won't be collected. – Daniel Oct 25 '11 at 02:43
  • @Dani: I would refer you to the answer in my link, where I show that the compiled code is identical regardless of where you declare the variable. And while you're there, read Eric Lippert's comment. – StriplingWarrior Oct 25 '11 at 02:50
  • It's a duplicate question, but I don't think most people asking this question would be using those keywords. – Terry Price Jan 07 '16 at 13:58
2

Perhaps you could check out an old test that I once did regarding another conversation. Variable declaration. Optimized way

The results turned out that it was faster to redefine but not as easy on memory.

My simple test. I initialised an object 100,000,000 times and it is was apparently faster to create a new one instead of re-using an old one :O

    string output = "";
    {
        DateTime startTime1 = DateTime.Now;
        myclass cls = new myclass();
        for (int i = 0; i < 100000000; i++)
        {
            cls = new myclass();
            cls.var1 = 1;
        }
        TimeSpan span1 = DateTime.Now - startTime1;
        output += span1.ToString();
    }

    {
        DateTime startTime2 = DateTime.Now;
        for (int i = 0; i < 100000000; i++)
        {
            myclass cls = new myclass();
            cls.var1 = 1;
        }
        TimeSpan span2 = DateTime.Now - startTime2;
        output += Environment.NewLine + span2.ToString() ;
    }
    //Span1 took 00:00:02.0391166
    //Span2 took 00:00:01.9331106

public class myclass
{
    public int var1 = 0;
    public myclass()
    {
    }
}
Community
  • 1
  • 1
Craig White
  • 13,492
  • 4
  • 23
  • 36
  • The compiler tends to drastically optimize code, so these results don't really show anything. – aleph_null Oct 25 '11 at 03:06
  • Benchmarks like this will almost always show some variation even in identical code due to factors like caching and other programs running on the computer at the same time, so it isn't surprising that you got slightly different results running this. I just ran the code twice and on the second time through both timespans had exactly the same value. – StriplingWarrior Oct 25 '11 at 03:27
  • Span1 takes more time because you are actually creating 100000001 classes. j/k :P – Andrew Feb 16 '22 at 17:38
0

To provide a real life example:

I just finished writing a .obj model loader which, of course, contains some nested loops. I declared all my variabeles above my loops but then I started wondering the same thing as the OP and found this thread. So I tried and moved all variable declarations to the first point in my loop where I use them and actually saw a small performance gain. A model that previously took 380 ms on average to load (370-400 ms actually) now consistently loads about 15-20 ms faster. This is just about 5% but nontheless an improvement.

My loop construct consists of just a foreach-loop and a nested for-loop but also contains a lot of if-statements. I moved 5 variable declarations, most of which are arrays of strings and ints.

Jupiter
  • 1,421
  • 2
  • 12
  • 31
  • 2
    The perceived performance gain here is probably not from the code changes you made. Measuring performance like this is tricky because it can be affected by memory pressure, other running processes, and caching, which are all largely outside your control. I'd be curious to see a well-written benchmark that shows any difference like you're describing. – StriplingWarrior Jan 07 '16 at 23:40
0

UPDATE:

if your are using the same type of variable as the loop you could do what I originally sugested:

for (int  i = 0,  myvar = 0; i < 100; i++) {
    //some logic
}

otherwise don't worry about it as others already suggested

@phoog, thx for checking the answer

Kris Ivanov
  • 10,476
  • 1
  • 24
  • 35
  • That really isn't going to solve anything as you're still doing string manipulations inside of a loop, which can become expensive due to the immutability of strings. – Scott Dorman Oct 25 '11 at 02:40
  • 1
    how exactly did u get all that from the OP, there is no mention about string manipulation, all he is asking to hide the scope of the variable in the same time not to declare on each iteration – Kris Ivanov Oct 25 '11 at 02:42
  • Your for loop won't compile. Try it. You can't declare/initialize multiple variables with var, and multiple declarations in the same statement must have the same type. – phoog Oct 25 '11 at 05:03
  • @Kris Ivanov I removed my downvote. For the record, the original code was something like `for (var i = 0, myvar = ""; ...; ...)` – phoog Oct 26 '11 at 21:15
0

I believe this would be a performance problem. Since the VM would need to allocate memory to store a reference to the String every loop. Even though the reference may be to the same String instance, allocating memory every time it goes around the loop would not be preferable.

Lionel
  • 428
  • 3
  • 10
  • 1
    Declaring a variable does not allocate memory. – StriplingWarrior Oct 25 '11 at 03:28
  • @StriplingWarrior References need memory too. – Lionel Oct 25 '11 at 03:37
  • 1
    Variables are often able to be stored in CPU registers and never need to use any memory at all. When there aren't enough registers to hold all the necessary variables, a fixed location is allocated on the stack when the method is invoked, and that location is reused. So no matter how many times you iterate over the `for` loop, assigning the variable there won't cause any more memory to be allocated. – StriplingWarrior Oct 25 '11 at 03:46
  • @StriplingWarrior So you're saying that the same location allocated on the stack is being reused for all variables that don't fit onto the registers? (BTW, I'm not too sure, but where is the stack stored physically in C#?) – Lionel Oct 25 '11 at 03:55
  • 2
    A full explanation is more complicated than I can explain in a comment, but as a rule of thumb, if you declare and use fifty variables throughout your method, you'll have roughly fifty memory slots allocated to store them, regardless of whether the variables are declared in a loop. If the compiler can see that you're only using those fifty variables one at a time, it can reuse the same slot of memory. So the named variables themselves are purely for the programmer's convenience. The heap is a giant block of memory that grows and shrinks as you call and return from methods. – StriplingWarrior Oct 25 '11 at 04:03
  • 1
    @StriplingWarrior Thanks for that. Learn something new everyday. Did not know the compiler was smart enough to reuse the memory in those cases. – Lionel Oct 25 '11 at 04:08
  • 1
    @StriplingWarrior don't you mean the stack grows and shrinks as you call and return from methods, not the heap? – phoog Oct 25 '11 at 05:00
  • @StriplingWarrior Yes. Bad habit of using the word memory to mean either. – Lionel Oct 25 '11 at 05:11
  • @phoog: Yup, that's what I meant. Thanks for the correction. – StriplingWarrior Oct 25 '11 at 06:16
-1

Yes, that would create a memory usage problem. I don't believe it would result in a memory leak as the Garbage Collector would eventually collect the unused objects, but that will have a negative impact on the performance of the application.

I would recommend you use a string builder declared outside the scope of the for loop.

Frazell Thomas
  • 6,031
  • 1
  • 20
  • 21
  • How does it create a "memory usage problem"? Strings are immutable, so every string assignment results in a new string object anyway. StringBuilder may be completely inappropriate to use here. – Andrew Barber Oct 25 '11 at 02:40
  • @AndrewBarber The memory usage problem would be the result of creating new strings on each iteration of the loop due to string immutability. Each new string uses memory and would result in increases in memory usage until the next run of the Garbage Collector. – Frazell Thomas Oct 25 '11 at 02:42
  • @AndrewBarber: How is a `StringBuilder` inappropriate? Strings are immutable, so each time through the loop you're creating a new instance, which will lead to higher memory consumption. – Scott Dorman Oct 25 '11 at 02:43
  • 1
    String is immutable. It does not matter where the string is declared - a new instance is created and needs to be GC'ed. It makes no difference. He's not performing aggregate concatenation here, so StringBuilder is not appropriate. – Andrew Barber Oct 25 '11 at 02:44
  • Assigning a string does not create a new string object. The code sample given does not create any new memory on the heap. However, if the string is being used for manipulation, using a StringBuilder declared outside the loop would be wise. – StriplingWarrior Oct 25 '11 at 02:47
  • 2
    @StriplingWarrior Why would the variable be initialized inside the scope of the loop if it isn't to be manipulated? If the desire is just to test for an empty string he would be better off using String.Empty constant or String.IsNullOrEmpty helper methods. – Frazell Thomas Oct 25 '11 at 02:55
  • @FrazellThomas: Since the question was about the scope of the variable, the whole question of string manipulation is beside the point. But as Andrew Barber pointed out, if he's building a new string in each instance of the `for` loop, then using a `StringBuilder` will likely have little effect, and could actually be detrimental. – StriplingWarrior Oct 25 '11 at 03:20
-1

It won't exactly decrease performance or cause a memory leak, but it is still something to be cautious of.

Strings are immutable, which means that once created, they can't be changed. By creating a new string inside the loop, you are creating at least n string variables. If you're trying to do string manipulation inside a loop, you should consider using a StringBuilder instead.

Scott Dorman
  • 42,236
  • 12
  • 79
  • 110
  • I'm glad you mention StringBuilder, but just to clarify: `string myVar = ""` does not create a new string. It just declares the variable's starting value as pointing to the memory location taken up by `string.Empty`. Constant string values are interned by the .NET compiler. – StriplingWarrior Oct 25 '11 at 02:41
  • 2
    the question has nothing to do with string manipulation at all – Kris Ivanov Oct 25 '11 at 02:43
  • 1
    @StriplingWarrior: Yes, it will be interned by the compiler. However, there is a natural assumption made that if a string variable is declared inside the loop it is to perform additional string manipulations, especially since it's being set to String.Empty initially. In that case, as soon as there is another string manipulation, a new string instance will be created so this can potentially lead to higher memory usage. – Scott Dorman Oct 25 '11 at 02:46
  • 1
    Actually, because he's starting each loop with an empty string, I would say that means he *won't* benefit from using StringBuilder. StringBuilder would only help if he's using the for loop to build a single string across multiple iterations. – StriplingWarrior Oct 25 '11 at 02:54
-1

Unless the compiler somehow optimizes your code, declaring a variable inside a for loop will require the allocation of new variables and the collection of old ones. That being said, the compiler does a really good job at optimizing your code.

If you want a quick way to test your two scenarios, use the StopWatch class to measure how much time it takes to execute each case. My guess is that this difference will be nonexistent to negligible.

aleph_null
  • 5,766
  • 2
  • 24
  • 39