1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Node.js の out of memory エラーが起きそうになったら例外を投げて通知する

Posted at

はじめに

Node.jsのバッチを保守していると、データ増加に伴いメモリー不足で処理が落ちてしまうことがありました。
エラー発生時にはChatworkに通知が飛ぶようにしていたのですが、そのときは通知が飛びませんでした。

そこで、メモリー不足で処理が落ちる前に、ある程度やばそうな量のメモリーを使っている時点で、警告を飛ばすようにしてみました。

処理内容

プログラムは次のような状態でした。

yabaiyo.js
var メモリーを圧迫する変数 = []

function すごく繰り返す処理 (繰り返す回数) {
  for (var i = 0; i < 繰り返す回数; i++) {
    メモリーを圧迫する変数.push(new Array(10000))
  }
}

try {
  すごく繰り返す処理(1000000)
} catch (e) {
  チャットワークに警告を送信('やばいよ')
}

function チャットワークに警告を送信 (メッセージ) {
  console.log(メッセージ + 'をチャットワークに通知しました。')
}

これを実行すると、下記のようなログが出て処理が止まります。


<--- Last few GCs --->

[5414:0x100000000]     4874 ms: Mark-sweep 1824.4 (2051.4) -> 1824.4 (2044.9) MB, 692.6 / 0.0 ms  (average mu = 0.075, current mu = 0.014) allocation failure GC in old space requested


<--- JS stacktrace --->

==== JS stack trace =========================================

(省略)

FATAL ERROR: Ineffective mark-compacts near heap limit Allocation failed - JavaScript heap out of memory

(省略)

zsh: abort      node yabaiyo.js

やばいのにChatworkに通知が飛びません。

改善

これを防ぐために、次のような関数を用意しました。

多分ほぼアウトオブメモリー.js
var v8 = require('v8')

function 多分ほぼアウトオブメモリー () {
  var stats = v8.getHeapStatistics()

  var 五百メガバイト = 500 * 1024 * 1024

  var ここを超えるとやばそう = stats.heap_size_limit - 五百メガバイト

  return stats.total_heap_size > ここを超えるとやばそう
}

「すごく繰り返す処理」の中に、「多分ほぼアウトオブメモリー」を判定する条件文を入れて、やばそうだったら例外を投げて「チャットワークに警告を送信」するようにしました。

function すごく繰り返す処理 (繰り返す回数) {
  for (var i = 0; i < 繰り返す回数; i++) {
    メモリーを圧迫する変数.push(new Array(10000))
    // ↓ ここに追加
    if (多分ほぼアウトオブメモリー()) {
      throw new Error('多分ほぼアウトオブメモリー')
    }
  }
}

ファイルの全体像は下記になります。

yabaiyo.js
var v8 = require('v8')

function 多分ほぼアウトオブメモリー () {
  var stats = v8.getHeapStatistics()

  var 五百メガバイト = 500 * 1024 * 1024

  var ここを超えるとやばそう = stats.heap_size_limit - 五百メガバイト

  return stats.total_heap_size > ここを超えるとやばそう
}


var メモリーを圧迫する変数 = []

function すごく繰り返す処理 (繰り返す回数) {
  for (var i = 0; i < 繰り返す回数; i++) {
    メモリーを圧迫する変数.push(new Array(10000))

    if (多分ほぼアウトオブメモリー()) {
      throw new Error('多分ほぼアウトオブメモリー')
    }
  }
}


try {
  すごく繰り返す処理(1000000)
} catch (e) {
  チャットワークに警告を送信('やばいよ')
}

function チャットワークに警告を送信 (メッセージ) {
  console.log(メッセージ + 'をチャットワークに通知しました。')
}

こうすることで、実行したときに次のように出力されます。

$ node yabaiyo.js

やばいよをチャットワークに通知しました。
1
0
0

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
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?