Deleting large Javascript objects when process is running out of memory

javascript, memory-leaks, memory-management, mongodb, node.js

Solution

`delete` in javascript is NOT used to delete variables or free memory. It is ONLY used to remove a property from an object. You may find this article on the `delete` operator a good read.

You can remove a reference to the data held in a variable by setting the variable to something like `null`. If there are no other references to that data, then that will make it eligible for garbage collection. If there are other references to that object, then it will not be cleared from memory until there are no more references to it (e.g. no way for your code to get to it).

As for what is causing the memory accumulation, there are a number of possibilities and we can't really see enough of your code to know what references could be held onto that would keep the GC from freeing up things.

If this is a single, long running process with no breaks in execution, you might also need to manually run the garbage collector to make sure it gets a chance to clean up things you have released.

Here's are a couple articles on tracking down your memory usage in node.js: http://dtrace.org/blogs/bmc/2012/05/05/debugging-node-js-memory-leaks/ and https://hacks.mozilla.org/2012/11/tracking-down-memory-leaks-in-node-js-a-node-js-holiday-season/.

Problem

I'm a novice to this kind of javascript, so I'll give a brief explanation: I have a web scraper built in `Nodejs` that gathers (quite a bit of) data, processes it with `Cheerio` (basically `jQuery` for `Node`) creates an object then uploads it to mongoDB. It works just fine, except for on larger sites. What's appears to be happening is: - I give the scraper an online store's URL to scrape - Node goes to that URL and retrieves anywhere from 5,000 - 40,000 product urls to scrape - For each of these new URLs, Node's `request` module gets the page source then loads up the data to `Cheerio`. - Using Cheerio I create a JS object which represents the product. - I ship the object off to MongoDB where it's saved to my database. As I say, this happens for thousands of URLs and once I get to, say, 10,000 urls loaded I get errors in node. The most common is: ``` Node: Fatal JS Error: Process out of memory ``` Ok, here's the actual question(s): I think this is happening because Node's garbage cleanup isn't working properly. It's possible that, for example, the `request` data scraped from all 40,000 urls is still in memory, or at the very least the 40,000 created javascript objects may be. Perhaps it's also because the MongoDB connection is made at the start of the session and is never closed (I just close the script manually once all the products are done). This is to avoid opening/closing the connection it every single time I log a new product. To really ensure they're cleaned up properly (once the product goes to MongoDB I don't use it anymore and can be deleted from memory) can/should I just simply delete it from memory, simply using `delete product`? Moreso (I'm clearly not across how JS handles objects) if I delete one reference to the object is it totally wiped from memory, or do I have to delete all of them? For instance: ``` var saveToDB = require ('./mongoDBFunction.js'); function getData(link){ request(link, function(data){ var $ = cheerio.load(data); createProduct($) }) } function createProduct($) var product = { a: 'asadf', b: 'asdfsd' // there's about 50 lines of data in here in the real products but this is for brevity } product.name = $('.selector').dostuffwithitinjquery('etc'); saveToDB(product); } // In mongoDBFunction.js exports.saveToDB(item){ db.products.save(item, function(err){ console.log("Item was successfully saved!"); delete item; // Will this completely delete the item from memory? }) } ```

Original source