Reputation: 4193
I'm using Humble Finance to plot a series of data one point at a time to achieve a time-lapse effect. My code is below, but I'd like to explain it first:
If you're not familiar with HF, its initialization function takes three JavaScript arrays (priceData, volumeData, and summaryData), which it then plots onto three graphs. These arrays each contain several arrays of XY pairs.
In my program, I declare three empty "graph" arrays (priceData, volumeData, and summaryData), then get values from a database and put them into "master" JavaScript arrays of arrays called priceDataOrig, volumeDataOrig, and summaryDataOrig. Rather than passing these arrays to HF and plotting all the data at once, I call a function UpdateGraph() which calls itself every 40 ms. UpdateGraph() pushes one value (actually, an array containing an XY pair) at a time from the master arrays into their corresponding graph arrays, then calls the HF initialization function (passing it the graph arrays), drawing the three graphs. After 50 points are in the graph arrays, I start shifting out the oldest points before pushing new ones, so that no more than 50 points per graph are plotted at once.
Also, I'm using jQuery's load() to load the graph, so whenever the user clicks a "Go" button, graph.php (which handles everything described above) is loaded into a div on the page and begins graphing point by point. The idea is that the user should be able to click Go whenever they'd like to reload the graph and watch the time lapse again.
So now to my problem: in my test program, I'm plotting around 500 values total, so this is not a large data set by any means. When Go is clicked the first time, all the values are plotted fine. However, the browser's memory usage skyrockets (I've tried in both Firefox and Chrome), and when the user clicks Go again, the browser crashes entirely partway through the plotting. I'm at a total loss as to why this is happening -- I've tried null-ing all the arrays after plotting is finished, etc.
Does anyone have any ideas? Here's my graph.php code, slightly modified for clarity:
<?php
#Queries the DB and constructs the data strings assigned to JavaScript arrays below,
#An example might be: $priceData = '[[0,100.34],[1,108.31],[2,109.40],[3,104.87]]';
?>
<script>
//Global variables used in UpdateGraph():
//The "master" arrays -- I'm just using the same data for all of
//them for now (an array containing around 500 arrays of XY pairs)
var priceDataOrig = <?php echo $priceData; ?>;
var volumeDataOrig = <?php echo $priceData; ?>;
var summaryDataOrig = <?php echo $priceData; ?>;
var priceData = [],
volumeData = [],
jsonData = [];
i = 0,
pointsToShowAtOnce = 50,
totalPoints = priceDataOrig.length,
updateRate = 40; //milliseconds
UpdateGraph();
//Periodically updates the graph to show time lapse, adding one new point at a time
function UpdateGraph() {
//Only add a new point if all the points haven't already been added
if (i != totalPoints) {
//Add a new point to each array
priceData.push(priceDataOrig[i]);
volumeData.push(volumeDataOrig[i]);
summaryData.push(jsonDataOrig[i]);
if (i >= pointsToShowAtOnce) {
//We're showing the amount of points we want to show, so remove the oldest point
priceData.shift();
volumeData.shift();
jsonData.shift();
//Sets the new X values for these points -- not really pertinent to
//my question, it works the same if this block is commented out.
var pLen = priceData.length;
var j, c = 0;
for (j = 0; j < pLen; j++) {
priceData[j][0] = c;
volumeData[j][0] = c;
c++;
}
}
//Load the graph itself. 'humblefinance' is just a div on the page.
HumbleFinance.init('humblefinance', priceData, volumeData, summaryData);
i++;
//This function calls itself at the interval in
//updateRate until all the points have been drawn
setTimeout('UpdateGraph()', updateRate);
} else {
//I null these out here even though it doesn't seem necessary.
//It doesn't help though.
priceDataOrig = null;
volumeDataOrig = null;
summaryData = null;
jsonDataOrig = null;
priceData = null;
volumeData = null;
jsonData = null;
}
}
</script>
<div id="humblefinance"></div>
Upvotes: 3
Views: 1531
Reputation: 24334
Try a minor change to HumbleFinance. In the init method these functions are called:
this.buildDOM();
this.attachEventObservers();
These appear to be one-time config functions that you would only want to be run the first time you update the graph. There seem to be a lot of elements created and events bound, that would get done again and again, consuming more memory each time, since they are never released.
The easiest way would be to add a parameter to init
so you can conditionally exclude this part, or alternatively separate out the code that actually draws the graph as a separate method. In the end I think you only want those setup procedures called once.
Upvotes: 2
Reputation: 2594
2 ideas.
1 - Debuggers sometimes cause memory leaks. Does this happen with firebug / devtools turned off?
2 - Taking a quick peek at the code for HumbleFinance.js, it looks like the graphs are appended to the container, rather than replacing what's there. Something like this might help before calling init:
$('#humbledata')[0].innerHTML = ''
Or however jQuery likes you to do these things.
Upvotes: 1