Observer and memory leaks?

Hello everyone,

Just wanted to ask a question about observers.

Collection.find({
	status:'error',
}).observe({
	added(w) {
		new myClass(w._id).storeEndDate();
	},
});

In this simple pattern I wanted to know if the new myClass object previously created will be collected by the garbage collector ?

I’ve heard in many videos about memory management in Javascript that class creation inside callback loop are not collected since the runtime doesn’t know if we we still use it or no. I am right ?

If so how do I clean up this object ?

like so ?

Collection.find({
	status:'error',
}).observe({
	added(w) {
		const classObject = new myClass(w._id).storeEndDate();
                classObject = null; // does this will tell the global.gc() to clear this up ?
	},
});

Thank you in advance for the answer :slight_smile:

I don’t see any reason for this not to be garbage collected. Generally speaking you want to avoid unintentionally leaving a reference to an object. This happens most often when you create a closure that you didn’t realize. I don’t see that happening here.

1 Like

Cool!

So could you make me a tiny example of a memory leak using closure?

And one other question is how do I track down memory leak server side?

Bunch of chrome dev tools are helpful (I might not of use them all) but they are mainly for the client side right?

Not at all. This is what I use for dbeugging client and server in Meteor using VSCode:

1 Like

So technically your example if done unintentionally could be considered a memory leak, albeit a very very tiny one that isn’t likely to grow to cause a problem. The reason for this would be that you haven’t stopped your observer and it will continue to run for any changes to that cursor. This could however be completely intentionally because you want it to continue to run indefinitely.

Where this becomes a problem is if you do this repeatedly and never stop the observers. This probably happens most frequently in Meteor when the low level publish api is used inside a publication. An observer gets started on a cursor and is intended to run until the publication is stopped but the developer forgets to stop the observe in the publications onStop callback. When the publication stops the observer continues to run and as more and more and more subscriptions to the publication happen, more observers are started and never stopped. This not only leaks memory, but also CPU cycles because the observers all run when the data changes. Failure to stop observer handles is a really good example of a closure based memory leak.

Meteor.publish('customPub', function() {

  var subHandle = SomeCollection.find().observeChanges({
    added: (id, fields) => {
      this.added("collectionName", id, fields);
    },
    changed: (id, fields) => {
      this.changed("collectionName", id, fields);
    },
    removed: (id) => {
      this.removed("collectionName", id);
    }
  });

  this.ready();

  this.onStop(() => {
    //we should really call subHandle.stop() here, but we don't
  });
});

On the client side, failure to stop subscriptions would be equivalent to this, but would also leak server resources as well so it creates double the issue.

5 Likes

IBM has a pretty good resource if you want to learn more about memory leaks in JS.

Thanks for the ressources, and the tiny example, i’ll read it in order to understand it even better.

I’m starting to get the point here, after analysing the ressources used by my server and the overall pub/sub i saw (using apm server monitoring) that many many documents where fetch on a specific collection.

Does a subscription done in the template OnCreated callback is deleted when the template reach the onDestroyed callback ? (i think yes).

How the reuse of observer work ?

And on the publication context, is it better to create our own observer and manage ourself the way data can reach the client, or should I still return a Mongo cursor listening on a specific query ?

Didn’t we could go that far with this tool, awesmome!