vmpowerio/chartjs-node

Memory leak while generating a lot of server side graphs

Closed this issue · 6 comments

Hi,

I am generating a lot of images on server side. During the process, Node is consuming a lot of memory (~ 1.5 GB).
I am calling chartNode.destroy(), still memory is not getting released.

Does anyone knows, where else there could be a memory leak?

PFB my code:

	var ChartjsNode = require('chartjs-node');
	var chartNode = new ChartjsNode(335, 250);

	return chartNode.drawChart(chartJsOptions)
		.then(() => {
			return chartNode.getImageDataUrl('image/jpeg')
		})
		// chart is created		
		// write to a file
		.then(() => {
			return chartNode.writeImageToFile('image/jpeg', 'temp/testimage' + GLOBAL_CHART_COUNT + '.jpeg')
		})
		.then((out_img) => {
			console.log(out_img)
			// chart is now written to the file path
			chartNode.destroy();
			chartJsOptions = null;
		});

Hey @varsha2409 I would check to see if something is holding on to the chartNode reference.

Often times when you see these kinds of issues it is due to a large object (like chartNode which contains a virtual DOM) that sits high in scope and never gets dereferenced for garbage collection.

Hey @sedouard did you find anything?
I analysed the heap dump, there are many ChartElement, Chart.Controller and other Chart related objects.
I even did a force GC after every chart is created, these elements were still present.

@varsha2409 are you able to copy/paste the full context you're running this library in? I'm interested in seeing how it is repeatedly called. I suspect you are holding on to a references and thats why you're experiencing a leak.

@varsha2409 I've got a PR open, #43, that may address your issues--any chance you could give my fork a go to see if it helps you at all?

Hey guys,

I'm still having trouble with this. Calling destroy is not removing the instance of the chartNode.

I am using v1.7.1

Any insight?

return new Promise(function (resolve, reject) {
  var chartNode = new Chart(_options.width, _options.height)

  var options = {...}

  chartNode.drawChart(options)
        .then(() => {
          if (_options.base64) {
            // if base64 was in the query then return base64 data
            return chartNode.getImageDataUrl(_options.type)
          } else {
            // else return the image buffer
            return chartNode.getImageBuffer(_options.type)
            }
        })
        .then(image => {
          resolve(image)
        })
        .finally(() => {
          chart.destroy()
        })
        .catch(error => {
          reject(error)
        })
    })

@tscritch I think u want to be destroying the chart instance in ur finally block? chartNode.destroy ?