はじめに
メモリサイズの取得方法を列挙するのみで、メモリサイズの解析に関する詳細には立ち入りません。
お品書き
参考
- Guide: How To Inspect The Memory Usage in Node.Js
- Node.jsアプリケーションを、Google ChromeのDevToolsでデバッグする - CLOVER
- 5 Commands to Check Memory Usage on Linux | Linux.com | The source for Linux information
本文
個別のオブジェクトの使用サイズを見る
特定のオブジェクトがメモリを大きく使うことを想定している時に、実際にどれぐらい使っているのか確かめたいことがあります。次のような用途です。
- 実際の使用量を元に、負荷がn倍になった時の利用メモリ量の予想
- メモリ使用量のチューニングの効果測定
例えば、itemMap
というオブジェクトが、大量の値を登録しているMapインスタンスを持つ場合を考えます。HEAP SNAPSHOT
を取得して、Mapのインスタンスから大きそうなインスタンスを探すと、該当するMapインスタンスを見つけることができます。
- 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が走ったタイミングでイベントを送出します。このイベントを使うことで、正確な「使用しているオブジェクトの総メモリ量」が取得できます。これを継続して取得し、増加傾向があればメモリリークの有無を検知できます。
説明を読んだだけで実際は使っていません。