8

次のような単純な http サーバーがあるとします。

var http = require('http');

http.createServer(function (req, res) {
  req.on('data', function (data) {
    console.log('Got some data: ' + data);
  });

  req.on('end', function () {
    console.log('Request ended!');
  });

  res.end('Hello world!');
}).listen(3000);

したがって、基本的にはデフォルトの 101 サンプルであり、これまでのところ特別なことは何もありません -読み取り可能なストリームのdataおよびendイベントにサブスクライブすることを除いて。reqこれらのイベントが不要になった場合、それらのイベントのサブスクライブを解除する必要があるのでしょうか?

それとも、読み取り可能なストリームが終了すると自動的にクリアされますか?

このようなコードでメモリ リークが発生する可能性はありますか?

4

1 に答える 1

17

(この回答には、node.js ソース コードの適切な部分へのリンクが含まれています)

質問に答える前に、イベントについて話しましょう。これを行う場合:

emitter.on('an-event', listener);

listenerに添付されたリストに追加されemitterます。その後、emitterがイベントをトリガーすると、リストを反復処理することにより、イベントにサブスクライブしているすべてのリスナーに通知します。node.js イベント エミッターの魔法は、そのリストを自分で宣言または管理しないことです。

ただし、 を呼び出すたびに、後方参照エミッター -> リスナー.on()を作成します。この参照により、リスナーが GC によって収集されなくなり、購読を解除しないと「リーク」が発生します。

通常、エミッターはリスナーの前に破棄されるため、これは node.js ではあまり頻繁には発生しませんが、これが発生する実際のケースは、時々再接続する長時間の接続 (Twitter ストリーミング API を考えてください) がある場合です。イベントの登録を解除しないと、古い接続からイベントを取得し、それらが新しい接続に適用されると考える可能性があります。これにより、新しい接続が閉じられたと考えることができます。

node.js は、リスナーの登録解除を忘れている可能性があると判断した場合、悪名高い「リークの可能性が検出されました」というメッセージを出力します。

あなたの例に戻ります:

ソケット (req+res) が最初に破棄されるため、これによってリークが発生することはありません。エミッターなので、node.js はすべてのリスナーを強制的に削除します

于 2013-10-31T14:17:22.850 に答える