Возможная утечка памяти JavaScript при обработке массивов? - PullRequest
3 голосов
/ 22 июня 2011

Я использую Humble Finance , чтобы построить серию данных по одной точке за раз для достижения эффекта замедленной съемки.Мой код приведен ниже, но я хотел бы сначала объяснить это:

Если вы не знакомы с HF, его функция инициализации принимает три массива JavaScript (priceData, volumeData и summaryData), которые затем выводятся на экран.на три графика.Каждый из этих массивов содержит несколько массивов пар XY.

В моей программе я объявляю три пустых «графовых» массива (priceData, volumeData и summaryData), затем получаю значения из базы данных и помещаю их в «master»Массивы JavaScript массивов с именами priceDataOrig, volumeDataOrig и summaryDataOrig.Вместо того, чтобы передавать эти массивы в HF и выводить все данные сразу, я вызываю функцию UpdateGraph (), которая вызывает себя каждые 40 мс.UpdateGraph () выдвигает одно значение (на самом деле, массив, содержащий пару XY) из главных массивов за раз в их соответствующие графовые массивы, затем вызывает функцию инициализации HF (передавая ей графовые массивы), рисуя три графика.После того, как в массивах графиков появилось 50 точек, я начинаю смещать самые старые точки перед тем, как нажимать новые, чтобы на графике одновременно отображалось не более 50 точек.

Кроме того, я использую загрузку jQuery () для загрузки графика, поэтому всякий раз, когда пользователь нажимает кнопку «Перейти», graph.php (который обрабатывает все, что описано выше) загружается в div на странице и начинает построение графика пункт за точкой.Идея состоит в том, что пользователь должен иметь возможность нажимать кнопку «Го» всякий раз, когда он захочет перезагрузить график, и снова посмотреть промежуток времени.

Итак, теперь к моей проблеме: в моей тестовой программе я строю графики вокругВсего 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>

Ответы [ 2 ]

2 голосов
/ 23 июня 2011

Попробуйте небольшое изменение в HumbleFinance. В методе init эти функции называются:

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

Похоже, что это одноразовые функции конфигурации, которые вы хотите запускать только при первом обновлении графика. Кажется, что создано много элементов и привязаны события, которые будут выполняться снова и снова, каждый раз потребляя больше памяти, поскольку они никогда не освобождаются.

Самым простым способом было бы добавить параметр к init, чтобы вы могли условно исключить эту часть или альтернативно выделить код, который фактически рисует график, как отдельный метод. В конце концов, я думаю, вы хотите, чтобы эти процедуры настройки были вызваны только один раз.

1 голос
/ 23 июня 2011

2 идеи.

1 - отладчики иногда вызывают утечки памяти. Это происходит с выключенным firebug / devtools?

2 - Быстрый взгляд на код для HumbleFinance.js, похоже, что графики добавляются к контейнеру, а не заменяют то, что там. Примерно так может помочь перед вызовом init:

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

Или как бы jQuery не хотел, чтобы вы это делали.

...