处理数组时可能存在JavaScript内存泄漏问题?

3
我正在使用Humble Finance绘制一系列数据,以实现时间间隔效果。以下是我的代码,但我想先解释一下:
如果您不熟悉HF,它的初始化函数需要三个JavaScript数组(priceData、volumeData和summaryData),然后将它们绘制到三个图表上。这些数组每个都包含多个XY对的数组。
在我的程序中,我声明了三个空的“graph”数组(priceData、volumeData和summaryData),然后从数据库中获取值并将它们放入名为priceDataOrig、volumeDataOrig和summaryDataOrig的“master”JavaScript数组的数组中。我不是将这些数组传递给HF并一次性绘制所有数据,而是调用一个UpdateGraph()函数,该函数每40毫秒调用一次自身。UpdateGraph()将一个值(实际上是包含一个XY对的数组)从主数组推送到相应的图形数组中,然后调用HF初始化函数(传递图形数组),绘制三个图形。当图形数组中有50个点时,我开始移除最旧的点,然后推入新的点,以便一次只绘制不超过50个点的图形。
此外,我正在使用jQuery的load()函数来加载图表,所以每当用户点击“Go”按钮时,页面上的一个div中就会加载处理上述所有内容的graph.php,并开始逐点绘制图表。想法是用户应该能够在需要重新加载图表并再次观看时间流逝时随时单击Go。
现在来说我的问题:在我的测试程序中,我总共绘制了约500个值,因此这绝不是一个大数据集。第一次单击Go时,所有值都被正确绘制出来。然而,浏览器的内存使用量飙升(我已经尝试过在Firefox和Chrome中),当用户再次单击Go时,浏览器在绘制过程中部分崩溃。我完全不知道为什么会发生这种情况——我已经尝试在绘制完成后将所有数组置空等等。
有人有什么想法吗?这是我的graph.php代码,稍作修改以便更清晰地理解:
<?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>

我不确定,但可能会发生这种情况,因为setTimeout('UpdateGraph()', updateRate);是从函数内部调用的。如果我没有搞错(我可能会XD),JS只要函数在使用中就不会释放内存。您应该在页面加载时设置超时,而不是在函数内部设置。 - Rafael Herscovici
据我所知,除非函数调用自身,否则无法确保每40毫秒调用一次该函数。我遇到的问题是在多次运行整个时间跨度并每次重新加载脚本到div后发生的。因此,似乎JS在重新加载graph.php后仍然继续使用内存。 - user428517
我同意无法确保每40毫秒调用一次函数,因为JS是客户端脚本,较慢的计算机需要更长时间。但是,如果你在函数外运行setTimeout,它仍然会尝试按指定的间隔执行。 如果你说JS在页面重新加载后仍然继续运行(这实际上不太可能),那么你可能在运行计算机上遇到问题,而不是在函数中。 - Rafael Herscovici
2个回答

2

尝试对HumbleFinance进行微小的更改。在init方法中,会调用以下函数:

this.buildDOM();
this.attachEventObservers();

这些似乎是一次性的配置函数,您只需要在更新图表时第一次运行它们。看起来创建了很多元素并绑定了事件,这些会一遍又一遍地完成,每次消耗更多的内存,因为它们从未被释放。

最简单的方法是向 init 添加一个参数,以便可以有条件地排除此部分,或者将实际绘制图表的代码分离为单独的方法。最终,我认为您只想调用那些设置程序一次。


非常感谢,jamietre,看起来问题已经解决了 - 我应该更仔细地查看库的那一部分。 - user428517

1

2个想法。

1-调试器有时会导致内存泄漏。在关闭firebug / devtools的情况下,是否会发生这种情况?

2-快速查看HumbleFinance.js的代码,看起来图表是附加到容器中的,而不是替换原有内容。在调用init之前使用类似以下代码的东西可能会有所帮助:

$('#humbledata')[0].innerHTML = ''

或者无论jQuery希望你如何做这些事情。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接