2013-04-18 10 views
10

v0.10.4nodejs setTimeoutメモリリーク?

ここでは、増え続けるメモリ使用量になり、単純なループです:私は間違って何をやっている

function redx(){ 
     setTimeout(function(){ redx() },1000); 
     console.log('loop'); 
} 

redx(); 

は?

EDIT

OKは、単にスコープでタイムアウトオブジェクトを参照するために提案を試み、ガベージコレクションは、約40秒後でキックないと思われ、ここでTOPからログを省略しています:

3941ルート20を0 32944 7284 4084 S 4.587 3.406 0:01.32ノード
3941ルート20 0 32944 7460 4084 S 2.948 3.489 0:01.59ノード
3941ルート20 0 32944 7516 4084 S 2.948 3.515 0:01.68ノード
3941ルート20 0 33968 8400 4112 S 2.948 3.928 0:02.15ノード
3941ルート20 0 33968 8920 4112 S 3.275 4.171 0:02.98ノード
3941ルート20 0 33968 8964 4112 S 2.948 4.192 0:03.07ノード
3941ルート20 0 33968 9212 4112 S 2.953 4.308 0:03.16ノード
3941ルート20 0 33968 9212 4112 S 2.953 4.308 0:03.25ノード
3941ルート20 0 33968 9212 4112 S 3.276 4.308 0:03.35ノード
3941ルート20 0 33968 9212 4112 S 2.950 4.308 0:03.44ノード

+0

信じられないほど、私は昨日自分自身を疑っていた。私の推測では、ノードは無名関数のクロージャを収集しないということです。 – dualed

+0

お使いのオペレーティングシステムは何ですか? – dualed

+0

私はこれをARCHでテストしています。 – crankshaft

答えて

4

なしあなたが関数nodejsのスコープ内でタイムアウトオブジェクトを参照しているのであれば、それはガベージコレクションを正しく行います。

function redx(){ 
     var t = setTimeout(function(){ redx() },50); 
     console.log('hi'); 
} 

redx(); 
+0

ありがとう、私はあなたのコードをテストし、残念なことに私の問題を解決しないと私はメモリ消費量に顕著な違いは表示されません。 – crankshaft

+0

修正、私はちょうどこれをもう一度見て、メモリの使用量は、最初は増加し続けてから約40秒後にピークに達します! – crankshaft

+0

奇妙なことに、私は明らかにメモリ使用量の増加を見て、初期値に戻っています(私はgcが起動すると思います) –

3

実際には、V8ガベージコレクタが動作する方法かもしれないと思います。

私のシステムでは、ノードヒープが48 MBまで増加して安定する傾向があるので、プログラムを長時間実行すると、メモリ消費は最終的に安定します。

ノードを起動するには、V8コマンドラインオプションの1つである--trace_gcフラグを使用してGCを開始するタイミングを知ることができます。

Redisで最初に試してみると、各呼び出しでRedisから体系的に接続/切断していました。これはゴミを生成する傾向があります。一度接続を開いて何度も使用することになっています。それにもかかわらず、私がこれをしても、メモリ消費は安定する傾向があります。ここでのRedisと、この例のメモリ消費の進化は次のとおりです。ここで

// something close to your initial function (when Redis was still in the picture) 
function redx(){ 
    var client = redis.createClient(); 
    client.get("tally", function(err, reply) { 
     client.quit(); 
    }); 
    setTimeout(function(){ redx() }, 50); 
} 

Evolution of memory consumption with Redis connect/disconnect

は、60メガバイト後の安定化が非常に明白であるように思われます。

+0

ありがとう、はいoriginaly私はこれがredis/memcacheの問題だと思ったが、コードを最小限にとどめた後、setTimeoutだけがこのリークを引き起こしていることがわかった。私が新しい接続を開いていた理由は、これが何ヶ月も続くかもしれないということです。そして、その時間の間にローカルホスト接続を開いておくことが信頼できるものかどうかは確信できませんでした。 – crankshaft

+0

上記のグラフを確認できます。 Nodejsはしばらくしてメモリ消費を安定させるようです。これは、ほとんどのGCで非常に一般的です。私は、setTimeoutループで 'redx()'を呼び出す隔離されたスコープを生成することによって同じ結果を得ました。私は 'setTimeout(redx.bind(null)、50);'をコールして同じグラフを表示しました。私は上記の例で推測しているが、 'var client = ...'は次のループの後に到達不能になるので、しばらくするとGarbageが収集されるので、メモリリークも適用されないはずです。 RedisにMem Leakが生成されるかもしれませんが、これは議論の対象外です。 –