ヘッドサイズのNodejsメモリ漏洩


オンライン環境でメモリの漏洩に遭遇し、3日間の模索を経て、解決しました.
pm 2バージョンをv 3で交換してください.5.1 v 3に下げる.4.1
この結論についてはまだあまり満足していないので,正真正銘だ.しかし、ここ数日の経験を記録しておくと、この文を読んでいるあなたに役立つかもしれません.

前言(励まし)


幸いなことに、私は今回十分な時間を持って検査に行って、他のことが邪魔していません.しかし、オンライン上でメモリの漏れが発生し、ビジネスコードのバグよりも解決しにくく、頭皮がしびれるのがつらい.理由は次のとおりです.
  • プロジェクトコードは複雑です.「漏れ点」を調べると、まるで海で針をすくうようだ.
  • オープンフロントエンドモード.暇のないnodeに気を配るmodulesモジュール
  • 無形の圧力.データを証拠にする時間が必要で、時間などが長ければ長いほど、圧力はますます
  • になります.
    精力or能力があるかどうかにかかわらず、メモリ漏洩を解決する最善の実践は、積極的な心理状態+冷静な問題の位置づけだと思います.(そう、これは今のところ問題を解決していないあなたに言ったことです)

    メモリ増加の原因


    この記事を見てくださいjs Memory Leaks: A Practical Guide
  • グローバル変数
  • コードキャッシュ
  • 閉パッケージ
  • ...

  • Anyway、実はどんな理由があっても、主にV 8 GCの解放が得られない.クラシックなコードを投げます.
    function calc(data) {
      return Math.round((data / 1024 / 1024) * 100) / 100 + " MB";
    }
    function logger() {
      let mem = process.memoryUsage();
      console.log(new Date(), "memory now:", calc(mem.rss));
    }
    var theThing = null;
    var replaceThing = function() {
      logger();
      var originalThing = theThing;
      var unused = function foo() {
        if (originalThing) {
          console.log("    ,  originalThing    someMethod    ");
        }
      };
      theThing = {
        longStr: new Array(1000000).join("*"),
        someMethod: function() {
          console.log("      ,     ");
        }
      };
      console.log("parse");
    };
    setInterval(replaceThing, 10);

    実行して間もなく、20 Mから数百Mに急上昇した.その原因を究明すると、やはり閉鎖引用がタイムリーに破棄されなかったためだ.
    具体的な原因は以下の通りです.
    unusedは呼び出されていませんが、originalThingが含まれ、theThingを指します.theThingには定義時にsomeMethodメソッドがあります.これは、originalThingが参照されているため、unusedでは解放されていない閉パケットです.

    メモリの「チェック」


    関連資料を照会したことがある場合は、heapdumpというモジュールが頻繁に現れるはずです.ここでは、プロジェクトのメモリ状況を監視するためにどのように使用するかを説明します.もちろんmemwatchも...

    インストール

    npm install heapdump -S

    もしあなたが十分に幸運であれば、次のような問題が発生するに違いありません.
    error: #error This version of node/NAN/v8 requires a C++11 compiler

    元のバージョンが低すぎて、linuxシステムのgccなどの関連ライブラリを更新する必要があります.
    以下のインストール手順を参照してください.
    #    repo   
    wget http://people.centos.org/tru/devtools-2/devtools-2.repo
    mv devtools-2.repo /etc/yum.repos.d
    
    #     
    yum install devtoolset-2-gcc devtoolset-2-binutils devtoolset-2-gcc-c++
    
    #     
    mv /usr/bin/gcc /usr/bin/gcc-4.4.7
    mv /usr/bin/g++ /usr/bin/g++-4.4.7
    mv /usr/bin/c++ /usr/bin/c++-4.4.7
    
    #       ,         
    ln -s /opt/rh/devtoolset-2/root/usr/bin/gcc /usr/bin/gcc
    ln -s /opt/rh/devtoolset-2/root/usr/bin/c++ /usr/bin/c++
    ln -s /opt/rh/devtoolset-2/root/usr/bin/g++ /usr/bin/g++
    
    #     ,    
    gcc --version

    もちろんシステムはwindowで、node-gyp、pythonのインストールでエラーが発生する可能性があります.
    以下のnpmモジュールを推奨します.
    windows-build-tools
    ワンタッチで関連コンポーネントをインストールする依存性(時間がかかるため、静かに待つだけです).Windows対応のNET Framework、pythonなどのプラグインをインストールしてあげます.
    npm install --global --production windows-build-tools

    使用


    問題を特定するためのコンソール出力をオンラインで簡単に作成しました.
    var heapdump = require("heapdump");
    let startMem = process.memoryUsage();
    
    function calc(data) {
      return Math.round((data / 1024 / 1024) * 10000) / 10000 + " MB";
    }
    //      koa
    router.all("/foo", async (ctx, next) => {
      let mem = process.memoryUsage();
      logger.debug("memory before", calc(startMem.rss), "memory now:", calc(mem.rss), "diff increase", calc(mem.rss - startMem.rss));
      // ...
    });

    これにより、システムのメモリ消費量がリアルタイムで表示されます(起動直後と比較して):
    2019-09-06 16:30 +08:00: [2019-09-06T16:30:06.700] [DEBUG] transfer - memory before 55.5898 MB memory now: 95.1484 MB diff increase 39.5586 MB
    2019-09-06 16:30 +08:00: [2019-09-06T16:30:07.724] [DEBUG] transfer - memory before 56.2148 MB memory now: 69.8438 MB diff increase 13.6289 MB
    2019-09-06 16:30 +08:00: [2019-09-06T16:30:10.406] [DEBUG] transfer - memory before 56.2148 MB memory now: 70.5977 MB diff increase 14.3828 MB
    2019-09-06 16:30 +08:00: [2019-09-06T16:30:11.018] [DEBUG] transfer - memory before 55.5898 MB memory now: 95.4219 MB diff increase 39.832 MB
    2019-09-06 16:30 +08:00: [2019-09-06T16:30:12.827] [DEBUG] transfer - memory before 55.5898 MB memory now: 95.6797 MB diff increase 40.0898 MB
    2019-09-06 16:30 +08:00: [2019-09-06T16:30:12.952] [DEBUG] transfer - memory before 55.5898 MB memory now: 94.9688 MB diff increase 39.3789 MB

    必要に応じてメモリをキャプチャするスナップショットルーティングを追加します.
    router.all("/snapshot", async (ctx, next) => {
      heapdump.writeSnapshot("./dump-" + Date.now() + ".heapsnapshot", function(err) {
        if (err) console.error(err);
      });
    });

    chromeのprofileパネルにインポートし、前後の2つのファイルの変化を比較し、問題を特定します.
    すべてがうまくいけば、問題コードにすぐに位置決めできます.しかし、実際にはもっと難しく、頭がつかめない.

    推測の可能性


    上記の「チェック」操作に従って問題点に位置していない場合は、このセクションが役に立つかもしれません.
    まず、自分が着手したプロジェクトの用途、技術を知っておく必要があります.それはあなたの問題を調査するのにもっと意味があります.
    たとえば、このプロジェクトはnodeの中間層サービスに基づいてapiインタフェースを変換します.バックエンドapiサービスの「アップグレード」により、各クライアントのリリース時差をスムーズにします.(サービスはapi呼び出しにパフォーマンスのボトルネックがある可能性がありますか?)
    テクノロジースタック:sequelize+koa+pm 2(プロジェクトの主なフレームワークに精通し、大きなテクノロジーの方向から着手)
    幸いなことに、あるプロジェクトBはこのプロジェクトと似ていて、技術的に少し違いがあります.
    上記のように、メモリ漏洩の可能性のあるいくつかの原因を推測した(参考資料付):
  • コードの問題
  • コード論理グローバルキャッシュの問題
  • Difference between Map and WeakMap in JavaScript

  • プロジェクト自体の負荷能力
  • アクセス(プロジェクトAがプロジェクトBより高い)
  • データベースのクエリーに対する衝撃(sequelize)
  • sequelize 4.37.7メモリ漏れ
  • sequelizeにおけるladash api変数は
  • を回収していない.
  • ログ読み書きスタック(log 4 js)
  • PM2 cluster + log4js?望ましくない組み合わせ

  • サードパーティ依存
  • pm2
  • pm2 memory leak



  • 検証#ケンショウ#


    可能な理由
    テストモード
    検証結果
    コメント
    コード問題
    ab圧力測定
    ok
    しかし、重視を増やさなければならない.
    sequlizeバージョンの問題
    ab圧力測定
    ok
    試行を見合わせる.現在4.42.0を使用しているため、オンラインではバージョンの変更のリスクを負うことができません.
    Ladash _.template
    ab圧力測定
    ok
    現状を維持する.
    log 4 js背圧の問題があります
    ab圧力測定
    ok
    pm 2&log 4 jsの使用は友好的ではなく、代替案がある前に(例えばwinston)、現状を維持します.
    pm 2バージョンの問題
    ラインダウンバージョン3.5.1->3.4.1
    検証対象
    プロジェクトB使用3.4.1

    結論


    この2,3日,オンライン状況からpm 2バージョンを修正するとメモリ漏洩が制御される.次の結論に基づいて検証手順を反転します.
  • devtoolsを使用して、1日のメモリの違いを発見し、TIMERWRAP指標が急増した:TIMERWRAPはNodeの中でTimer関連定義であり、タイマが規則的な無限リフレッシュで性能を占有しているかどうかを推測した.
  • を引き続き調べてみると、pm 2には「合わない」metrics心拍検出があり、settimeoutなどのコードがあるかどうかがわかりました.
  • 資料を見て、関連issusの中でコードがleakがオンラインプロジェクトの関連コードを見ていると言っていることを発見しました.確かにこの問題のコードがあります.なぜif/elseがメモリの漏れをもたらすのか、時間があれば検討してください.domのようなeventバインドは解除されていないと推定される.

  • リファレンス


    私はただ知識点の“加工者”で、更に多くの内容は原文のリンクを参照してください
    、同時に原作者の支払いに感謝します:
  • JavaScriptメモリリークチュートリアル
  • ESModule
  • を深く解析
  • Difference between Map and WeakMap in JavaScript
  • ES6 Map vs WeakMap vs plain Objects – Describing the differences
  • sequelize 4.37.7メモリ漏れ
  • sequelizeにおけるladash api変数は
  • を回収していない.
  • PM2 cluster + log4js?望ましくない組み合わせ
  • pm2 memory leak
  • heapdumpのインストールを記録し、node-gyp rebuild failedの問題
  • を報告する.
  • Finding And Fixing Node.js Memory Leaks: A Practical Guide
  • JavaScriptメモリ最適化
  • An interesting kind of JavaScript memory leak
  • 4 JavaScriptメモリの漏洩および
  • を回避する方法
  • JavaScript閉パッケージ詳細
  • 私について


    もしこの文章があなたに役に立つと思ったら、いいねをクリックしたり、もっと多くの道友に共有したりしてください.
    コードをスキャンして私の微信の購読番号に注目することもできます-[フロントエンドの雨のお父さん]、最初の時間は技術の文章を受け取って、仕事の余暇は私は出力し続けます
    最後に読書に感謝します.あなたたちの支持は私の書く最大の原動力です.