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

发布于 2024-11-16 20:17:42 字数 3468 浏览 4 评论 0原文

我正在使用 Humble Finance 一次绘制一系列数据,以实现延时效果。我的代码如下,但我想先解释一下:

如果您不熟悉 HF,它的初始化函数需要三个 JavaScript 数组(priceData、volumeData 和summaryData),然后将其绘制到三个图表上。这些数组每个都包含多个 XY 对数组。

在我的程序中,我声明了三个空的“图形”数组(priceData、volumeData 和summaryData),然后从数据库中获取值并将它们放入称为priceDataOrig、volumeDataOrig 和summaryDataOrig 的“主”JavaScript 数组中。我没有将这些数组传递给 HF 并立即绘制所有数据,而是调用函数 UpdateGraph(),该函数每 40 毫秒调用一次自身。 UpdateGraph() 一次将一个值(实际上是一个包含 XY 对的数组)从主数组推送到相应的图形数组中,然后调用 HF 初始化函数(将图形数组传递给它),绘制三个图形。当图形数组中有 50 个点后,我开始移出最旧的点,然后再推送新的点,这样每个图形一次绘制的点不超过 50 个。

另外,我使用 jQuery 的 load() 来加载图表,因此每当用户单击“Go”按钮时,graph.php(处理上述所有内容)就会加载到页面上的 div 中并开始逐点绘制图表。这个想法是,用户应该能够在任何时候想要重新加载图表并再次观看时间流逝时单击“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>

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>

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

千寻… 2024-11-23 20:17:42

尝试对 HumbleFinance 进行微小的更改。在 init 方法中调用这些函数:

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

这些似乎是一次性配置函数,您只想在第一次更新图形时运行它们。似乎创建了很多元素并绑定了很多事件,这些操作会一次又一次地完成,每次都会消耗更多的内存,因为它们永远不会被释放。

最简单的方法是向 init 添加一个参数,以便您可以有条件地排除这部分,或者将实际绘制图形的代码作为单独的方法分离出来。最后,我认为您只希望这些设置过程被调用一次。

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.

彩扇题诗 2024-11-23 20:17:42

2个想法。

1 - 调试器有时会导致内存泄漏。当 firebug / devtools 关闭时会发生这种情况吗?

2 - 快速浏览一下 HumbleFinance.js 的代码,看起来图表已附加到容器中,而不是替换其中的内容。在调用 init 之前,类似这样的事情可能会有所帮助:

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

或者无论如何 jQuery 喜欢你做这些事情。

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文