53

We are developing a single-page web app with ZK which constantly communicates with server and updates parts of its screens. Updating can be as frequent as 1s. During these updates, references to large ammounts of JS objects are lost and those objects have to be cleaned by garbage collector eventually.

As far as we've figured out, Chrome only runs its garbage collector on inactive tabs. This is a problem for us, because the app's tab is usually active and almost never refreshed, thus JS objects never get collected. If left active for enough time, the tab eventually crashes (Aww Snap message).

We need to initiate garbage collection manually. So far we've tried running Chrome with --js-flags="--expose-gc" and running gc(), but it throws an exception:

ReferenceError: gc is not defined

This doesn't happen on Firefox -- memory usage is more or less a constant.

Force refreshing the page is not an option.

We would be grateful for any and all suggestions.

EDIT: we've tried running window.gc() and gc() both on Chrome versions 23.0.1271.97 m and 25.0.1364.2 dev-m

Paulius K.
  • 813
  • 1
  • 7
  • 13
  • 6
    *"As far as we've figured out, Chrome only runs its garbage collector on inactive tabs"* No, that's incorrect. Chrome will run the GC whenever it feels it needs to, whether the tab is active or not. – T.J. Crowder Dec 19 '12 at 10:37
  • Have you tries using JavaScript's [`delete`](https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Operators/delete)? – Cerbrus Dec 19 '12 at 10:38
  • 5
    It's window.gc() but it's not the ultimate solution because AFAIK it works only on debug versions of Chrome. As Crowder pointed out Chrome will run it when needed so if your app leaks memory then what you should review your code to explicitly release allocated objects whenever possible. – Adriano Repetti Dec 19 '12 at 10:39
  • 4
    @Cerbrus: `delete` has nothing to do with memory management in JavaScript, except purely as a side-effect if you happen to use it to remove a property which is the only outstanding reference to an object. – T.J. Crowder Dec 19 '12 at 10:41
  • @T.J.Crowder: Yea, I know the `delete` doesn't necessarily trigger gc, but it could help in cleaning up objects, manually. Maybe I should've elaborated a little. – Cerbrus Dec 19 '12 at 10:43
  • 2
    @Cerbrus: :-) Just avoiding that myth continuing to be prepetuated (**wow** Brendan should have called it `remove` or something, but hey, he was under *massive* time pressure...). – T.J. Crowder Dec 19 '12 at 10:45
  • 1
    @T.J.Crowder: We have found an issue in [code.google.com](http://code.google.com/p/chromium/issues/detail?id=72146), where users also claim that GC doesn't happen unless tab is made inactive (7th comment). It is resolved as *WontFix*. It most possibly should work as you described, but for some reason doesn't. – Paulius K. Dec 19 '12 at 11:26
  • 1
    @guilty: I don't interpret that thread that way, I interpret it as someone saying the memory isn't released as soon as they think it should be, and someone saying they *think* they can cause the *Aw snap!* but providing zero supporting data for that. Clearly if you could crash Chrome by dragging images in repeatedly, that would not be a *WontFix* situation. – T.J. Crowder Dec 19 '12 at 12:08

3 Answers3

45

You can fetch code of Chrome Dev Tools, modify it so that ProfilerAgent.collectGarbage(); is called every now and then (it's a code that is called when you click 'Collect Garbage' button on the Timeline panel) and run Chrome with your version of DevTools using --debug-devtools-frontend flag.

However, this solution is quite extreme, try it only when you get really desperate. Till then, I propose profiling your application and checking out why v8 decides not to clean the garbage (or can't clean the garbage). Timeline panel of DevTools will help you out with this. Start with checking if 'Collect Garbage' button at the bottom of this panel really does its job, if not - you probably have a memory leak (at least, according to v8). If so, try leak-finder-for-javascript.

[EDIT] I removed info about chrome extension, as it turns out that gc() can be called from webpage code when --js-flags="--expose-gc" is used. At least on my 23.0.1271.64.

Konrad Dzwinel
  • 36,825
  • 12
  • 98
  • 105
  • 5
    It turns out you have to close all current Chrome processes before opening one with `--js-flags`. Now `gc()` seems to work. The 'Collect Garbage' button also works. Thanks, you've helped a lot. – Paulius K. Dec 19 '12 at 14:27
  • 2
    Is there any way to call from javascript?? – Saurabh Agrawal Apr 22 '19 at 10:13
  • In cases where you do not own the website in question, but you have control over the client you can install an extension that automatically reloads the page when an `Aw Snap` error occurred. An example is the `Oh No You Didn't` extension. Obviously this is a last resort work-around, but it can be useful for some rare use cases :) – Rens Tillmann Jul 21 '22 at 13:36
41

In Chrome Developer Tools, in the "Performance" tab, find the button that looks like a Garbage Can. Clicking on it forces the garbage collector to run. enter image description here

Note: older Chrome versions from around Chrome 53 had this button in the "Timeline" section, like this: enter image description here

jameshfisher
  • 34,029
  • 31
  • 121
  • 167
Nisim Joseph
  • 2,262
  • 22
  • 31
  • 15
    Newer versions have moved the Collect garbage button to the Performance tab in Developer Tools: https://i.stack.imgur.com/tguqy.png – Luiz Jul 05 '17 at 15:17
  • yes. you can press it as much as you want. and whenever you want. – Nisim Joseph Mar 02 '19 at 11:13
  • 1
    I believe in latest Chrome, this trash button is added now in the Memory section next to the record button. – aug Mar 29 '19 at 21:53
  • 1
    In mine there seems to be one in both Performance and Memory tabs. – SamB Aug 07 '19 at 03:45
5

I found a solution. Apparently Chrome leaks DOM nodes, at least in the current version (26.0.1410.65 right now)

I recorded dev tools timeline in my app and it showed the Event Listeners count going up and down rhythmically along with my app screen's contents, but the DOM Node count was steadily increasing over time, until the tab crashed.

I tried the latest Chrome Canary (28.0.1500.3) and they seem to have fixed the problem. DOM Node count graph now follows the same rhythmic pattern as the Event Listeners.

The thing that gets me is...why doesn't gmail ever crash? I usually keep a tab open for weeks at a time...

Partap Davis
  • 639
  • 6
  • 3