search
LoginSignup
33

More than 3 years have passed since last update.

posted at

updated at

Organization

Node.jsの使用メモリを観測する方法

はじめに

メモリサイズの取得方法を列挙するのみで、メモリサイズの解析に関する詳細には立ち入りません。

お品書き

参考

本文

個別のオブジェクトの使用サイズを見る

特定のオブジェクトがメモリを大きく使うことを想定している時に、実際にどれぐらい使っているのか確かめたいことがあります。次のような用途です。

  • 実際の使用量を元に、負荷がn倍になった時の利用メモリ量の予想
  • メモリ使用量のチューニングの効果測定

例えば、itemMapというオブジェクトが、大量の値を登録しているMapインスタンスを持つ場合を考えます。HEAP SNAPSHOTを取得して、Mapのインスタンスから大きそうなインスタンスを探すと、該当するMapインスタンスを見つけることができます。

スクリーンショット 2018-05-13 21.45.18.png

  • Shallow Size: インスタンス単体のサイズ。Mapや配列であればインスタンス単体のサイズより中身のサイズが知りたいです。この値にはあまり興味がありません
  • Retained Size: ずばり、Mapや配列の中身のサイズの合計

Retained Sizeを算出してくれるのが、めちゃくちゃ便利です。

HEAP SNAPSHOTを取得して、Mapのインスタンスから大きそうなインスタンスを探すYouTube動画を用意しました。DevToolsの使い方がわからない方はどうぞ。

Google ChromeのDevToolsでのDebugのはじめ方は、Node.jsアプリケーションを、Google ChromeのDevToolsでデバッグする - CLOVERを読んでください。

全体的なメモリ使用量の傾向を見る

メモリリークの有無を知りたい時に知りたい情報です。

process.memoryUsage()

Node.jsの標準API process.memoryUsage()を使います。
特に追加のリソースは必要ないので、ソースを変更できる場合は、一番手軽です。

このAPIを使って、デバッグプリントします。
例えば、次のソースコードを追加すれば、5分おきにメモリ使用量を標準出力に出力します。

// 定期的にメモリ使用量を吐き出す
setInterval(() => {
  const used = process.memoryUsage()
  const messages = []
  for (let key in used) {
    messages.push(`${key}: ${Math.round(used[key] / 1024 / 1024 * 100) / 100} MB`)
  }
  console.log(new Date(), messages.join(', '))
}, 5 * 60 * 1000)

ログの例です。

2018-05-13T11:39:46.293Z 'rss: 315.79 MB, heapTotal: 253.01 MB, heapUsed: 239.41 MB, external: 0.22 MB'
2018-05-13T11:44:46.308Z 'rss: 355.88 MB, heapTotal: 267.43 MB, heapUsed: 254.4 MB, external: 0.31 MB'
2018-05-13T11:49:46.323Z 'rss: 324.54 MB, heapTotal: 256.04 MB, heapUsed: 242.81 MB, external: 0.23 MB'
2018-05-13T11:54:46.338Z 'rss: 359.49 MB, heapTotal: 271.09 MB, heapUsed: 257.61 MB, external: 0.36 MB'
2018-05-13T11:59:46.353Z 'rss: 346.75 MB, heapTotal: 262.74 MB, heapUsed: 248.15 MB, external: 0.28 MB'
2018-05-13T12:04:46.368Z 'rss: 316.83 MB, heapTotal: 252.87 MB, heapUsed: 239.29 MB, external: 0.2 MB'
  • rss: プロセス全体が使っているメモリ使用量。topコマンドなどで出力させる値
  • heapTotal: プログラム中で作成したオブジェクトが使用しているメモリの総量

memwatch-next

process.memoryUsage()では、その瞬間の「使用しているオブジェクトの総メモリ量」は取れません。process.memoryUsage()は、要求された瞬間のメモリ使用量を取得しますが、その瞬間がGarbage Collectionの実行直後かはわかりません。つまり、process.memoryUsage()の出力する値には、すでに使っていないが解放されていないGarbageオブジェクトが含まれている可能性があります。

この問題に対応するためのnpmパッケージがmemwatch-nextです。Node.jsのC拡張を使って、Garbage Collectionが走ったタイミングでイベントを送出します。このイベントを使うことで、正確な「使用しているオブジェクトの総メモリ量」が取得できます。これを継続して取得し、増加傾向があればメモリリークの有無を検知できます。

説明を読んだだけで実際は使っていません。

その他の参考

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
What you can do with signing up
33