4

私はjavascriptを初めて使用し、毎秒Googleチャートをajaxデータで更新するコードでメモリリークを見つけるのに苦労しています。

私のコード(小さなテストケースに簡略化):

function TimeLine(id, max) {
    this.chart = new google.visualization.LineChart(document.getElementById(id));
    this.vals = new google.visualization.DataTable();
    this.vals.addColumn('number', 'Index');

    for (var i = 2; i < arguments.length; i++) {
        this.vals.addColumn('number', arguments[i]);
    }

    this.numCols = arguments.length - 2;
    this.max = max;
    this.index = 0;

    this.resourceOptions = {
        'title': 'Memory allocation',
            'width': 360,
        'height': 300
    };
}

TimeLine.prototype.Add = function () {

    if (this.vals.getNumberOfRows() > this.max) {
        this.vals.removeRow(0);
    }

    var row = [this.index];

    for (var i = 0; i < arguments.length; i++) {
        row.push(arguments[i]);
    }

    this.vals.addRow(row);

    this.chart.draw(this.vals, this.options);

    this.index++;
};

function onLoad() {
    window.Timeline = new TimeLine('gauges', 15, 'Alloc');
    drawCharts();
}

function drawCharts() {
    window.Timeline.Add(window.Timeline.index%3);

    setTimeout(drawCharts, 1000);
}

google.load('visualization', '1.0', {
    'packages': ['corechart']
});

google.setOnLoadCallback(onLoad);

64 ビット Ubuntu でクロム バージョン 29.0.1547.62 を使用しています。

私は JS のスコープ ルールに慣れていないので、(できれば) スコープとガベージ コレクションについて簡単に推論できるように、グラフをオブジェクトでラップしました。SO に関する類似の質問を多数見てきましたが、私のコードでリークが発生しないようにすることができる限りではありません。メモリ タイムラインを使用すると、drawCharts が呼び出されるたびにメモリが上昇していることがわかります。そのメモリのほとんどは GC されているようですが、約 1 時間後にはそのタブで最大 300 MB になり、タブがクラッシュします。目標は、サーバーの 1 つの現在の負荷を監視するシステムとして、このタブを長期間維持できるようにすることですが、現在、停止するまで数時間しか維持できません。

プロファイル タブでヒープ スナップショットを使用してみました。drawCharts を数回呼び出す前後のスナップショットを比較すると、リークされたオブジェクトはチャート自体の SVG 要素であるように見えますが、これらの結果を誤って解釈している可能性があります。

問題を再現しました:

http://jsfiddle.net/dv5nK/4/

約 20 分後、Chrome の about:memory ページに約 150 MB の高いメモリ消費量が表示され始めます。この効果は、setTimeout を 100 ミリ秒に短縮することで、より速く確認できます。

編集:メモリ使用量の統計を修正

4

4 に答える 4

2

これは既知のバグです。問題1 問題2

于 2013-09-08T17:24:21.133 に答える
0

私が気付いたのは、イベントリスナーが削除されていないため、要素がメモリから解放されていないことです。

私はこの行を疑う:

if (this.vals.getNumberOfRows() > this.max) {
    this.vals.removeRow(0);
}

削除する行にアタッチされているすべてのイベント リスナーを確実に削除する方法はありますか?

于 2013-09-08T17:00:08.860 に答える
0

Google チャートのメモリ使用量についても同じ問題がありました。Google コードの clearChart() 関数を変更することで問題を解決できました。

完全な答えは次のとおりです。

Google チャートの一定の再描画メモリの増加

于 2013-09-17T01:19:34.340 に答える