In my career, I've worked a lot with different programming languages, especially with C# and javascript.
During my years of development, I've faced a lot of performance issues, on Mobile and Desktop applications.
Often, the main reasons for performances lack are scripts.
Scripts are the main part of our website/applications, they weight a lot and they use a lot of resources, like CPU and RAM.
In Javascript, there isn't a manual garbage collector system (like c# or c++ malloc or free method), so you need to optimize the resources management part of your application to prevent memory leaks, zombie data or other performance issues.
But what can we do, as developers, to decrease the RAM usage for example?
we need to write good code, reuse resources and handle data smartly.
For example, don't declare variables inside a for loop until it is really necessary!
Why
A for loop is a looped method invocation, so a variable declared inside a for loop will exists inside the loop scope only, and it will be initialized
in every loop iteration! This means than a space in memory for the variable will be allocated in each loop cycle!
What the heck!
This fact, combined with the typeless Js language could create big memory leaks, performance issues, and other bad behaviors.
A simple, but effective method to recycle RAM is to declare variables once and reuse them when needed. The for loop is the simplest case but you can replicate this solution everywhere.
Example
BAD
Declare cursor inside the for loop and a string inside too.
for (let i = 0; i < 1000; i++) {
let logString = 'Current is: ' + i;
console.log(logString);
}
console.log('%o', window.performance.memory);
{totalJSHeapSize: 68876822, usedJSHeapSize: 46264582, jsHeapSizeLimit: 2197815296}
GOOD
Declare cursor and logString outside the for loop:
let logString = '';
let i = 0;
for (i = 0; i < 1000; i++) {
logString = 'Current is: ' + i;
console.log(logString);
}
console.log('%o', window.performance.memory);
{totalJSHeapSize: 57747133, usedJSHeapSize: 45757109, jsHeapSizeLimit: 2197815296}
As you can see the totalJSHeapSize in the second implementation is less than the first one (< 11129689byte ~ 11mb), the usedJSHeapSize too (< 507473byte ~ 0.5mb).
I know, this isn't a great saving, but with large projects, this could save your web application performances!
Conclusion
There are a lot of optimization we can use to boost our applications, and this solution is not only JS-related, you could use it with any language you use.
But I think JS is the best case to use, because it's not resource-optimized.
I hope you found this article useful or just interesting!
Top comments (45)
I really doubt this is right at all, and this is not a good experiment to show that it is right.
1) You're not recording the heap before hand, so it's impossible to know how much has actually changed
2) You're not running multiple experiments. The garbage collector is not deterministic, so you'll get slightly different numbers each time. At the least, you should be reporting an average over many trials.
3) You're logging to the console in this experiment. Logging to the console expends huge amounts of memory and CPU which are going to make the results far too variable to be useful.
For the record, when I tried measuring the difference, I saw no difference; the amount of memory that had been used by any single run was basically random, and neither was more or less than the other.
Remember the three rules of optimization:
1) Don't.
2) Don't, yet. (Experts only)
3) Profile before optimizing. Even if this experiment showed that variables inside loops use more memory, that wouldn't justify the blanket advice to not declare variables in loops, because that's probably not where most of your program is using its memory; instead of hurting readability and violating best-practices, you should find where your program is actually wasting most of its memory.
Seconding your answer.
Yes you're right, I'll keep your tips for the next time!
Don't wait until next time. This is harmful, bad advice. You should add a big fat disclaimer to the article that so you made mistakes here.
Please look further down the comments for a comment by Jan Hasebos. It would address your perception regarding the iterated declaration, while also respecting the variable scope of the for loop.
Really, you'd be better off saying the "bad" example is ok, while you feel the "good" example is better.
I added some thoughts below Jan to expand on this.
I want to buy you a beer
For loop-internal variables, this shouldn't actually save any memory on average. I mean, if the garbage collector is really stupid (most aren't), it might, but not much unless you've got a lot of variables inside the loop that are only ever primitives. OTOH, it should save some time, because you don't have to allocate memory on every loop iteration.
For the actual counter variable though, it's not as clear cut. In terms of runtime and memory usage, there should be near zero difference in the totals between these two code samples:
The reason is simple: Internally, that first part of the loop expression (the
i = 0
part) runs exactly once. So moving the counter declaration outside of the loop expressions just changes the scope, nothing else. Somewhat counter-intuitively, this may even make the loop run slower if you are accessing the counter inside the loop a lot (I know of no JS engine that actually has this issue, but a trivial naive implementation of the JS scoping rules would cause it to run slower).If, however, you can safely reuse the counter variable across multiple loops, then you might save some time this way, but you won't really save much space long-term. The important part there though is 'safely', you usually have to at least scope the declarations to the containing function so that you don't end up manipulating other loops states accidentally, so you're not likely to save much time either unless you're doing a lot of looping.
Came here to say this. Placing the
let
within the for expression doesn't mean it's being created every loop. It's only created once, it's more concise, and it's scoped to the for loops block. Unless you have good reason to (e.g. keeping track of a counter), to place it outside is just bad practice.Also, don't know about javascript, some compilers optimise your code so that variable declarations inside a loop when turn to machine code are placed outside the 'loop'.
You can never know how a compiler will ootimise your code. Interpreters are a whole different story. Correct me if I'm wrong. There are other things you can do to optimise your code and better manage memory. First thing is algorithm complexity and storing excess data or use blocks of code so you limit the life of a variable and etc.
There's definitely more important optimisations than worrying about a
for
loop. Unless you are looping through tens of thousands of objects - bit that's a whole different story.If it were almost anything but memory allocation, I would agree wholeheartedly. Allocating memory, however, is literally one of the slowest runtime operations possible in pretty much any language you care to name (coincidentally, this is most of why C++'s
std::string
is so slow compared to C-style strings, pretty much any call that 'mutates' a string involves allocating memory for a new one).The exact benefit may not be huge in terms of time, but it's a good habit to just write optimal code in cases like this where it's easy.
There are indeed other things you can do to optimize your code, but eliminating memory allocations (and de-allocations) is one of the easier ones that's consistently a win in most languages. That's one of the other reasons to group your variable declarations at the top of a function aside from making the code easier to read, some runtime environments and compilers will actually be able to further optimize things so that there are fewer allocations that need to be made that way.
Look, this article needs to be taken down. It's very harmful to novice programmers and more experienced programmers will probably just leave a comment saying "you're wrong". That being said, I feel bad for the author. He likely has no idea that this is bad advice and this is all probably discouraging. My advice for the author: please take the article down or revise it so that beginners don't draw incorrect conclusions. Afterwards, write your next article! I'd love to see you write about frontend or something else you're interested in!
Why? JavaScript has automatic garbage collection mechanism.
Yes sorry, I mean than "you cannot manually deallocate resources" like c# or c++ malloc or free
Sure you can, if you
null
an Object then it will be marked for GC. It may not happen immediately, but when the GC runs it will be cleaned up.developer.mozilla.org/en-US/docs/W...
C# has garbage collection and no way to manually free resources. It works the same as javascript, you can set all references to an object to
null
and then it will eventually be garbage collected. You can also force the garbage collector to run, but that is highly discouraged in almost all circumstances.Unfortunately we just have to trust that is what is happening but it's okay, we don't want to panic anyone. Can you see what I did there.
Just don't write in JavaScript if you need fast and memory efficient code.
This thing is premature optimization. You should prefer code clarity over efficienty until you absolutely need last one (about 1% of your code I suppose).
Declaring variables outside of your loop to use inside of a loop could cause unintended consequences if the code in the loop is complicated. Reusing variables might seem efficient until you need to fix a bug introduced by another developer.
Unless performance is really essential and in this case it's probably negligible, writing cleaner code is more important imo.
Pretty much everything here is wrong.
The iterator should be stack allocated, and is only initialized once anyway.
The logString variable is assigned to a new value each iteration and goes out of scope at the end, or at least gets reassigned. There aren't 1000 variables with heap string references waiting to be deallocated when the loop ends.
There is an excellent explanation by v8 developers of how memory allocation works in v8 JS engine.
I would read this before anyone jumps to conclusions.
Whoa, this is crazy. I have always dismissed the declaration inside the loop having a very minimal performance impact. Apparently my assumptions were wrong.
Thanks for this! Will definitely take note of this from here on out.
That's because it is incorrect. Please read the rest of the comments in this article for better explanations.
Thanks for the heads up!
Thanks a lot! Check this video from Unity, is for C# but some principles could be applied to general programming languages, it shows a lot of data optimization and performance boost using the Data-Driven programming pattern
Thanks! I definitely will watch it.
Please don't do this and take this article down. As others have mentioned, the experiment is flawed.
Don't prematurely optimize. It can lead to a number of problems:
Don't complicate your code unless absolutely necessary. Follow the KISS principal.
I recently found myself reviewing code from a senior software engineer that was filled with premature optimizations. It was very hard to read and created an abundance of code for what purpose? Just to save a negligible amount of time - we're talking far less than a millisecond. Orders of magnitude less than your standard network delay.
Don't be that engineer.
Don't encourage others to be that engineer.
Some comments may only be visible to logged-in visitors. Sign in to view all comments.