Any idea on garbage collector timer in javascript?
Suppose i run below script, will function and associated scope chained variable will go
for garbage collection exactly after 100ms? Or some margin?
I read one thread about garbage collection in stackoverflow, still i have this question.
Below are my questions?
Does any SYSTEM TIMER run for garbage collection task?
If no, is it EVENT based?, means if reference is no more present, garbage
collector will reclaim memory INSTANTLY.
function call_me() {
//calculate elapsed_time - code not given
if(elapsed_time <100)
{
setTimeout(call_me,25);
}
else{
final_call();
}
}
call_me();
Every user agent implements garbage collection differently. All user agents use the mark-and-sweep method on a periodic repetition, so there is no "instantly" about it; it will happen when it happens.
Each agent has different thresholds and mechanisms to determine when the GC does a pass. It isn't necessarily event-driven (purhaps you might say it is benchmark-driven, event-initiated), and certainly not based on a timer.
A function that passes out of scope is instantly eligible for garbage collection, but there's really no telling when it would happen.
This is really something that, from the developer perspective, you are not intended to think about. There isn't any way to stop or start GC, or any indication that it happened at all. Check out about:memory in Firefox for some interesting trivia (and there's a couple of dubious buttons down there to "control" the GC). That's about all you're going to get as far as it goes under the hood, and that data isn't available to scripts.
The garbage collector is non-deterministic.
Garbage will be collected some time after it becomes garbage.
A closure object passed to setTimeout will become garbage after it executes.
Anything beyond that is implementation-specific.
Related
Let's say I have a long running loop:
// Let's say this loop takes 10 seconds to execute
for(let i = 0; i <= 1000000; ++i) {
const garbage = { i };
// some other code
}
Can the garbage collector run during the loop, or it can only run when the application is idle?
I didn't find any documentation related to this, but because Node.js has the --nouse-idle-notification which in theory disables GC, makes me think that the GC only runs when the idle notification is sent (when the main thread is not busy).
I am asking this because my loop sometimes has spikes in execution time and want to know if it's possible that the GC might run during the loop, resulting in the lag spike.
V8 developer here. The short answer is that the GC can run at any time and will run whenever it needs to.
Note that the GC is a fairly complex system: it performs several different tasks, and does most of them in incremental steps and/or concurrently with the main thread. In particular, every allocation can trigger a bit of incremental GC work. (Which implies that by very carefully avoiding all allocations, you can construct loops that won't cause GC activity while they run; but it's never the case that loops accumulate garbage that can't get collected -- unless you have a leak in your code of course, where objects are unintentionally being kept reachable.)
Can the garbage collector run during the loop, or it can only run when the application is idle?
It absolutely can and will run during the loop.
Node.js has the --nouse-idle-notification which in theory disables GC
No, it does not. There is no way to disable GC. That flag disables one particular mechanism for triggering GC activity, but that only means that GC will be triggered by other mechanisms.
the GC only runs when the idle notification is sent (when the main thread is not busy)
No, the idea is to run some extra GC cycles when there is idle time, to save some memory when the application is not busy.
my loop sometimes has spikes in execution time and want to know if it's possible that the GC might run during the loop, resulting in the lag spike
That could be. It could possibly also have to do with optimization or deoptimization of the function. Or it could be something else -- the operating system interrupting your process or assigning it to another CPU core, for example, or hundreds of other reasons. Computers are complex machines ;-)
if you set a variable to null -- garbage collection is done immediately
No, it is not. Garbage collection is never done immediately (at least not in V8).
As a concept the garbage collector works in a separate thread since in this way it will not block the main thread (UI thread in most cases).
As for your example, there is no problem for the garbage collection thread running in "parallel" to this loop since the value there const garbage = {key: i} will not get removed as long as it is being referenced.
Also note that there are several generations that the garbage collector passes your values through before removing them completely.
I have a number of functions calling the next one in a chain, processing a rather large set of data to an equally large set of different data:
function first_step(input_data, second_step_callback)
{
result = ... // do some processing
second_step_callback(result, third_step);
}
function second_step(intermediate_data, third_step_callback)
{
result = ... // do some processing
third_step_callback(result);
}
function third_step(intermediate_data) { }
first_step(huge_data, second_step);
In third_step I am running out of memory (Chrome seems to kill the tab when memory usage reaches about 1.5 GB).
I think, when reaching third_step(), the input_data from first_step() is still retained, because first_step() is on the call stack, isn't it? At least when the debugger is running, I can see the data.
Obviously I don't need it anymore. In first_step() there is no code after second_step_callback(result, third_step);. Maybe if I could free that memory, my tab might survive processing a data set of this size. Can I do this?
Without seeing a lot more of what you're really doing that is using memory, it's hard for us to tell whether you're just using too much memory or whether you just need to let earlier memory get freed up.
And, memory in Javascript is not "owned" by stack frames so the premise of the question seems to make a bit of a wrong assumption. Memory in Javascript is garbage collected and is eligible for GC when no live, reachable code still has a reference to the data and will get garbage collected the next time the garbage collector gets to run (during JS idle time).
That said, if you have code that makes a succession of nested function calls like your question shows, you can reduce the amount of memory usage, by doing some of these things:
Clear variables that hold large data (just set them to null) that are no longer needed.
Reduce the use of intermediate variables that hold large data.
Reduce the copying of data.
Reduce string manipulations with intermediate results because each one creates block of memory that then has to be reclaimed.
Clear the stack by using setTimeout() to run the next step in the chain and allow the garbage collector a chance to do its thing on earlier temporary variables.
Restructure how you process or store the data to fundamentally use less memory.
I'm maintaining a JavaScript code where a function that does some heavy processing to generate arrays saves the results in a cache variable inside the function itself. It's implemented like this:
function heavyProcessingStuff(x) {
if(heavyProcessingStuff.cache == undefined)
heavyProcessingStuff.cache = [];
if(heavyProcessingStuff.cache[x] != undefined) {
return heavyProcessingStuff.cache[x]
} else {
return heavyProcessingStuff.cache[x] = x + 1
}
}
The weird thing is that there's a function executed when the page is unloaded that manually deletes every property of the cache variable, like this:
for (n in heavyProcessingStuff.cache) {
delete heavyProcessingStuff.cache[n]
}
I'm confused about why this was implemented this way.
Is this specific for some weird corner case? Is there any motivation to do so? Doesn't/shouldn't the browser garbage collect everything when the page closes?
Javascript uses garbage collection and it is best not to free memory explicitly. Good reading on this is in "De-referencing Misconceptions" in the article "Writing Fast, Memory-Efficient JavaScript".
A quote from the article:
It’s not possible to force garbage collection in JavaScript. You
wouldn’t want to do this, because the garbage collection process is
controlled by the runtime, and it generally knows best when things
should be cleaned up.
Without seeing the full context, there is one other possibility:
Earlier versions of IE (I know IE6 was susceptible), used a simple reference counting system for garbage collection. The trouble is that the DOM and JavaScript kept separate reference stacks.
This allowed for a situation to develop where the DOM (via an expando property) could hold onto a JavaScript reference -- and the JavaScript held onto a DOM reference.
This circular references would create a memory leak that lived on beyond the page, and the memory was only released when the page window was closed.
It was common to use the unload event to free memory and release any event handlers in an effort to avoid this.
In Chrome and Internet Explorer (or any browser that implements a process-per-tab model), you're right, there's absolutely no value. In fact, it's wasting CPU time to try and delete, since often when a tab is closed a process is killed, freeing up all non-shared resources.
For browsers that are a single process (Firefox still is, though progress is underway to change that), it's possible this could make the garbage collector do its work faster, if the reference counts get decremented to 0, but it's probably also pointless. Other than very old (IE6 for example) browsers, every modern garbage collector will probably sweep away everything on the next pass regardless of whether you explicitly remove references or not.
Does having an active Object.observe on an object prevent it from being garbage collected? Do you need to first call Object.unobserve to allow it to be garbage collected? Or does GCing an object remove all its active observers?
Observing an object does not keep it alive. Once the object dies, its observers simply won't receive any more events. At least that's true in V8's implementation, which is the only one so far. It's probably safe to assume that it will hold for other implementations as well, should this feature become standard some day.
However, observation keeps its active observers alive, plus some internal, heap-allocated data structures associated with each observer function. In fact, this additional data will only die when the function itself has also died, even if it has long ceased to observe anything.
I want to trigger JavaScript garbage collection. Is it possible? Why would I want to, or not want to, do this?
I went out on a small journey to seek an answer to one of your questions: Is it possible?
People all over town are saying that deleting the references will do the trick. Some people say that wiping the object is an extra guarantee (example). So I wrote a script that will try every trick in the book, and I was astonished to see that in Chrome (22.0.1229.79) and IE (9.0.8112.16421), garbage collection doesn't even seem to work. Firefox (15.0.1) managed without any major drawbacks apart from one (see case 4f down below).
In pseudo-code, the test goes something like this.
Create a container, an array, that will hold objects of some sort. We'll call this container Bertil here on.
Each and every object therein, as an element in Bertil, shall have his own array-container declared as a property. This array will hold a whole lot of bytes. We'll call any one of Bertil's elements, the object, Joshua. Each Joshua's byte array will be called Smith.
Here's a mind map for you to lean back on:
Bertil [Array of objects] -> Joshua [Object] -> Smith [Array of bytes] -> Unnamed [Bytes].
When we've made a mess out of our available memory, hang around for a sec or two and then execute any one of the following "destruction algorithms":
4a. Throw a delete operand on the main object container, Bertil.
4b. Throw a delete operand on each and every object in that container, kill every Joshua alive.
4c. Throw a delete operand on each and every array of bytes, the Smiths.
4d. Assign NULL to every Joshua.
4e. Assign UNDEFINED to every Joshua.
4f. Manually delete each and every byte that any Joshua holds.
4g. Do all of the above in a working order.
So what happened? In case 4a and 4b, no browser's garbage collector (GC) kicked in. In case 4c to 4e, Firefox did kick in and displayed some proof of concept. Memory was reclaimed shortly within the minute. With current hardcoded default values on some of the variables used as test configuration, case 4f and 4e caused Chrome to hang, so I can't draw any conclusions there. You are free to do your own testing with your own variables, links will be posted soon. IE survived case 4f and 4e but his GC was dead as usual. Unexpectedly, Firefox survived but didn't pass 4f. Firefox survived and passed 4g.
In all of the cases when a browser's GC failed to kick in, waiting around for at least 10 minutes didn't solve the problem. And reloading the entire page caused the memory footprint to double.
My conclusion is that I must have made a horrible error in the code or the answer to your question is: No we can't trigger the GC. Whenever we try to do so we will be punished severely and we should stick our heads in the sand. Please I encourage you to go ahead, try these test cases on your own. Have a look in the code were comment on the details. Also, download the page and rewrite the script and see if you can trigger the GC in a more proper way. I sure failed and I can't for the life of me believe that Chrome and IE doesn't have a working garbage collector.
http://martinandersson.com/dev/gc_test/?case=1
http://martinandersson.com/dev/gc_test/?case=2
http://martinandersson.com/dev/gc_test/?case=3
http://martinandersson.com/dev/gc_test/?case=4
http://martinandersson.com/dev/gc_test/?case=5
http://martinandersson.com/dev/gc_test/?case=6
http://martinandersson.com/dev/gc_test/?case=7
You can trigger manually JavaScript garbage collector in IE and Opera, but it's not recommended, so better don't use it at all. I give commands more just for information purpose.
Internet Explorer:
window.CollectGarbage()
Opera 7+:
window.opera.collect()
Garbage collection runs automatically. How and when it runs and actually frees up unreferenced objects is entirely implementation specific.
If you want something to get freed, you just need to clear any references to it from your javascript. The garbage collector will then free it.
If you explain why you even think you need to do this or want to do this and show us the relevant code, we might be able to help explain what your alternatives are.
Check your code for global variables. There may be data coming through an ajax call that is stored, and then referenced somewhere and you did not take this into account.
As a solution, you should wrap huge data processing into an anonymous function call and use inside this call only local variables to prevent referencing the data in a global scope.
Or you can assign to null all used global variables.
Also check out this question. Take a look at the third example in the answer. Your huge data object may still be referenced by async call closure.
This answer suggests the following garbage collection request code for Gecko based browsers:
window.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
.getInterface(Components.interfaces.nsIDOMWindowUtils)
.garbageCollect();
Came across this question and decided to share with my recent findings.
I've looked to see a proper handling of a WeakMap in Chrome and it's actually looks okay:
1) var wm = new WeakMap()
2) var d = document.createElement('div')
3) wm.set(d, {})
at this stage weak map holds the entry cause d is still referencing the element
4) d = null
at this stage nothing references the element and it's weakly referenced object, and indeed after a couple of minutes entry disappeared and garbage collected.
when did the same but appended the element to the DOM, it was not reclaimed, which is correct, removed from the DOM and still waiting for it to be collected :)
Yes, you can trigger garbage collection by re-loading the page.
You might want to consider using a Factory Pattern to help re-use objects, which will greatly cut down on how many objects are created. Especially, if you are continuously creating objects that are the same.
If you need to read up on Factory Patterns then get yourself this book, "Pro Javascript Design Patterns" by Ross Harmes and Dustin Diaz and published by APress.
I was reading Trevor Prime's answer and it gave me a chuckle but then I realized he was on to something.
Reloading the page does 'garbage-collect'.
location.reload() or alternatives to refresh page.
JSON.parse/stringify and localStorage.getItem/setItem for persistence of needed data.
iframes as reloading pages for user experience.
All you need to do is run your code in an iframe and refresh the iframe page while saving useful information into localStorage. You'll have to make sure the iframe is on the same domain as main page to access its DOM.
You could do it without an iframe but user experience will no doubt suffer as the page will be visibly resetting.
If it is true that there is no way to trigger a GC, as implied by the other answers, then the solution would be for the appropriate browser standards group to add a new JavaScript function to window or document to do this. It is useful to allow the web page to trigger a GC at a time of its own choosing, so that animations and other high-priority operations (sound output?) will not be interrupted by a GC.
This might be another case of "we've always done it this way; don't rock the boat" syndrome.
ADDED:
MDN documents a function "Components.utils.schedulePreciseGC" that lets a page schedule a GC sometime in the future with a callback function that is called when the GC is complete. This may not exist in browsers other than Firefox; the documentation is unclear. This function might be usable prior to animations; it needs to be tested.