Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Which code is more CPU/memory efficient when used with a Garbage Collected language?

I have these two dummy pieces of code (let's consider they are written in either Java or C#, all variables are local):

Code 1:

int a;
int b = 0;

for (int i = 1; i < 10 ; i++)
{
    a = 10;
    b += i;

    // a lot of more code that doesn't involve assigning new values to "a"
}

Code 2:

int b = 0;

for (int i = 1; i < 10 ; i++)
{
    int a = 10;
    b += i;

    // a lot of more code that doesn't involve assigning new values to "a"
}

At first glance I would say both codes consume the same amount of memory, but Code 1 is more CPU efficient because it creates and allocates variable a just once. Then I read that Garbage Collectors are extremely efficient to the point that Code 2 would be the more Memory (and CPU?) efficient: keeping variable a inside the loop makes it belongs to Gen0, so it would be garbage collected before variable b.

So, when used with a Garbage Collected language, Code 2 is the more efficient. Am I right?

like image 250
Broken_Window Avatar asked Jan 09 '15 17:01

Broken_Window


People also ask

What programming languages have garbage collection?

Garbage collection (GC) is a memory recovery feature built into programming languages such as C# and Java.

Which method can be used to request garbage collection?

System class has a static method gc(), which is used to request JVM to call garbage collector.

What is language processor garbage?

Garbage collection is the process in which programs try to free up memory space that is no longer used by objects. Garbage collection is implemented differently for every language. Most high-level programming languages have some sort of garbage collection built in.

Does C have garbage collection?

C does not have automatic garbage collection. If you lose track of an object, you have what is known as a 'memory leak'. The memory will still be allocated to the program as a whole, but nothing will be able to use it if you've lost the last pointer to it. Memory resource management is a key requirement on C programs.


2 Answers

A few points:

  • ints (and other primitives) are never allocated on heap. They live directly on the thread stack, "allocation" and "deallocation" are simple moves of a pointer, and happen once (when the function is entered, and immediately after return), regardless of scope.

  • primitives, that are accessed often, are usually stored in a register for speed, again, regardless of scope.

  • in your case a (and possibly, b as well, together with the whole loop) will be "optimized away", the optimizer is smart enough to detect a situation when a variable value changes, but is never read, and skip redundant operations. Or, if there is code that actually looks at a, but does not modify it, it will likely be replaced by the optimizer by a constant value of "10", that'll just appear inline everywhere where a is referenced.

  • New objects (if you did something like String a = new String("foo") for example instead of int) are always allocated in young generation, and only get transferred into old gen after they survive a few minor collections. This means that, for most of the cases, when an object is allocated inside a function, and never referenced from outside, it will never make it to the old gen regardless of its exact scope, unless your heap structure desperately needs tuning.

  • As pointed out in the comment, sometimes the VM might decide to allocate a large object directly in the old gen (this is true for java too, not just .net), so the point above only apply in most cases, but not always. However, in relation to this question, this does not make any difference, because if the decision is made to allocate an object in old gen, it is made without regard of the scope of its initial reference anyway.

From performance and memory standpoint your two snippets are identical. From the readability perspective though, it is always a good idea to declare all variables in the narrowest possible scope.

like image 192
Dima Avatar answered Oct 10 '22 17:10

Dima


Before the code in snippet 2 is actually executed it's going to end up being transformed to look like the code in snippet 1 behind the scenes (whether it be a compiler or runtime). As a result, the performance of the two snippets is going to be identical, as they'll compile into functionally the same code at some point.

Note that for very short lived variables it's actually quite possible for them to not have memory allocated for them at all. They may well be stored entirely in a register, involving 0 memory allocation.

like image 41
Servy Avatar answered Oct 10 '22 16:10

Servy