RailsでWebpackerを用いフロント開発していたところ、
webpacker-dev-serverがやたらとメモリを食い「heap out of memory」エラーが頻出していました。
Docker環境だからか、VM上でDockerを立てていたからか、仕様かわかりませんが、
最大メモリサイズを指定することでエラーがほぼ出なくなったので、同様の現象が起きている方は参考にしてみてください。
rails 6.0.3.1
ruby 2.6.6
webpacker 5.1.1
フロント:React(bin/webpack-dev-server利用)
サーバー:Rails
結論
bin/webpack-dev-server
に最大のメモリサイズを渡すと、最大メモリに近づいた時にメモリ解放を行ってくれました。
NODE_OPTIONS
の環境変数に--max-old-space-size=3072
を加えると最大メモリサイズを設定することができます。
#...
ENV["NODE_OPTIONS"] ||= "--max-old-space-size=3072"
#...
参考: Rails5.1のbin/webpacker-dev-serverでJavaScript heap out of memoryが起きた時の対処方
解説
開発はDockerを用いています。
Rails ServerとWebpackerを分けて、composeで管理をしています。
version: '3'
services:
db:
image: postgres:11.6-alpine
volumes:
- db:/var/lib/postgresql/data:cached
networks:
- web
environment:
TZ: Asia/Tokyo
webpacker:
build: .
command: ./bin/webpack-dev-server
volumes:
- .:/app:cached
- bundle:/usr/local/bundle:cached
- yarn:/node_modules:cached
ports:
- '3035:3035'
networks:
- web
environment:
NODE_ENV: development
RAILS_ENV: development
WEBPACKER_DEV_SERVER_HOST: 0.0.0.0
web:
build: .
command: sh -c "rm -f tmp/pids/server.pid && bundle exec rails s -p 3000 -b '0.0.0.0'"
volumes:
- .:/app:cached
- bundle:/usr/local/bundle:cached
- yarn:/node_modules:cached
ports:
- '3000:3000'
depends_on:
- db
- webpacker
networks:
- web
tty: true
stdin_open: true
environment:
WEBPACKER_DEV_SERVER_HOST: webpacker
volumes:
db:
bundle:
yarn:
networks:
web:
webpack-dev-serverを立てている状態でフロント部分を開発していると、JSを更新すると自動コンパイルされます。
コンパイル内容をメモリに格納していくようで、開発を進めていると更新の度にどんどんメモリが圧迫されます。
LIMITを超えたタイミングで「heap out of memory」エラーが発生しDockerを再起動する必要があります。(メモリを開放する)
Dockerのメモリ使用量はdocker stats
で確認することができます。
docker stats
=>
CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS
f697683f3b6e app_web_1 0.01% 116.4MiB / 3.859GiB 2.95% 84.5kB / 39.1kB 0B / 0B 19
c66e3f0371b1 app_db_1 0.00% 2.633MiB / 3.859GiB 0.07% 11.1kB / 60kB 0B / 0B 7
8bcd63949c32 app_webpacker_1 0.00% 859.9MiB / 3.859GiB 21.76% 92.6kB / 63kB 0B / 0B 11
MEM USAGE
がLIMITPIDS
を超えるとOOMエラーとなります。
MEM USAGE / LIMITPIDS
859.9MiB / 3.859GiB
WebpackerのDockerでは./bin/webpack-dev-server
コマンドを実行してます。
./bin/webpack-dev-server
では最終的にnode_modules/.bin/web-packer-dev
を実行しているようです。
参考: Webpacker使うなら最低限これだけは知っておいてほしいこと
./bin/webpack-dev-server
上ではnodeに環境変数を渡すことができます。
NODE_OPTIONSに--max-old-space-size=3072
を渡すと最大メモリサイズを指定してweb-packer-dev
を実行するようになります。
ご自身の環境に合わせて、任意のメモリサイズを指定してください。
#!/usr/bin/env ruby
ENV["RAILS_ENV"] ||= ENV["RACK_ENV"] || "development"
ENV["NODE_ENV"] ||= "development"
ENV["NODE_OPTIONS"] ||= "--max-old-space-size=3072"
require "pathname"
ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile",
Pathname.new(__FILE__).realpath)
require "bundler/setup"
require "webpacker"
require "webpacker/dev_server_runner"
APP_ROOT = File.expand_path("..", __dir__)
Dir.chdir(APP_ROOT) do
Webpacker::DevServerRunner.run(ARGV)
end
これでwebpack-dev-serverが最大メモリサイズに達したらメモリ解放されるようになりました。
メモリサイズが小さいため、頻繁にコンパイルするとメモリ解放が間に合わずOOMが出る時もありますが、かなり頻度が下がりました。
ご自身のスペックにあったメモリサイズを指定し、快適な開発に用いてください!