Jest のテストがメモリ不足で落ちまくっていたので、調査方法を調べてみた


TL;DR

簡易的にメモリの利用状況を知りたいのであれば次のオプションで jest 実行

実行例:

$ node --expose-gc ./node_modules/.bin/jest --runInBand --logHeapUsage
PASS  test/a.e2e-spec.ts (10.43 s, 160 MB heap size)
PASS  test/b.e2e-spec.ts (18.028 s, 197 MB heap size)
PASS  test/c.e2e-spec.ts (5.313 s, 215 MB heap size)
...

ちなみにこの実行例は実際にメモリリークが発生してるテストなので、リークしていなければ基本的にここの値は大きく変わらないはず

Google Chrome の inspect 機能を使いたい場合は次のオプションで jest 実行

実行例:

$ node --inspect-brk ./node_modules/.bin/jest --runInBand
Debugger listening on ws://127.0.0.1:9229/8ede11f0-7073-49bc-8e17-c16e661197d2
For help, see: https://nodejs.org/en/docs/inspector
# Chrome の chrome://inspect を開いて `inspect` ボタンをクリックするとを押すと進む
Debugger attached.

# Chrome の inspect ツールから breakpoint からの開始ボタンをクリックすると進む
RUNS  test/operations/event.e2e-spec.ts
...

ちなみに「これで最低限作業できる」ってオプションなので、「他のオプションを組み合わせたらもっと有用なデータが取れる」みたいなことはあるかもしれない。
もしご存知の方がいればコメントいただけると幸い。

オプションたち

--runInBand

Jestを実行したプロセスをそのままテスト実行プロセスとして利用し、全てのテストを直列で実行するデバッグ用のオプション。

--maxWorkers=1 と似ているが子プロセスを生成しないという点が違う。はず。
内部の実装を見ていないのでもしかすると同じなのかもしれないけど。

あと --runInBand--maxWorkers を同時に指定すると「バカなの?」と聞かれてコマンドが終了するので「わぁ、同時に指定しちゃった!どっちだ!」みたいなことにはならない。

--logHeapUsage

それぞれのテストでのメモリ使用量を出力してくれるオプション。
Jest の --runInBand オプションと node (v8) の --expose-gc オプションの設定が必要とのこと。

付けると時間情報の部分にメモリの利用量も表示されるようになる。

例:

# オプション無し
PASS  test/a.e2e-spec.ts (10.43 s)

# オプション有り
PASS  test/a.e2e-spec.ts (10.43 s, 160 MB heap size)

「メモリ利用量」と連呼しているけど、あくまでも「ヒープメモリ」であることには注意。
ただデバッグしてる時はそこまで気にする事でも無い。

--expose-gc

Node.js のオプションかと思ったら v8 のオプションらしい。
Web 上でのオプションのドキュメントは見当たらなかったのでオプションのありかだけ。

$ node --v8-options | grep expose-gc
  --expose-gc (expose gc extension)
  --expose-gc-as (expose gc extension under the specified name)

要は GC の情報を外部のアプリケーションからも触れるようにしてあげることでメモリの利用状況をより細かに取得できるようにしているんだと理解している。
--logHeapUsage を取りたいなら必要だと言われているから付ける。以上。

--inspect-brk

こちらは Node.js のオプション。
デバッグ用の inspector というサービスを立ち上げると同時に、ユーザーのアプリケーション実行前に Break してくれる。 --inspect というオプションを使うとデバッガーを接続した瞬間にアプリケーションコードが実行される。基本的に自分が手動で実行する分には --inspect-brk で良いと思う。

ToDo

あとで chrome を使った inspect 周りを書く

参考文献

https://dev.to/pustovalov_p/reducing-jest-memory-usage-1ina
「こうすれば Jest のメモリ利用状況把握できるよ」ってのを教えてくれた記事
ただ、結論が「--logHeapUsage するとその度に gc が走るからそれでパフォーマンス改善したよ。」だったので対処法は別途調べ中。

https://www.alexkras.com/simple-guide-to-finding-a-javascript-memory-leak-in-node-js/
Node のメモリリークのデバッグ方法を書いている記事
細かいメモリリークへの対応が書いてあるけど、「自分のコードにメモリの stats 出すコードを埋め込んで調査する」が基本スタイルなので、今回の jest のメモリ利用状況把握とは若干噛み合わない部分も。