Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationEventAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
0
Help us understand the problem. What are the problem?
Organization

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

はじめに

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

やばいよをチャットワークに通知しました。
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
0
Help us understand the problem. What are the problem?