リークハント

この投稿では、大規模なプロジェクトで特定のリークに対処した経験を説明しました。 多くの間違いがありましたが、誰かが役に立つかもしれません。



長い間、メモリリークは発生しませんでしたが、先日、ポジティブな悪魔が流れ始めました。 さらに、valgrind.memcheckにはわかりやすいものは何も表示されません-サーバーは長時間起動しますが、valgrindの下でそのような負荷の下でサーバーがフリーズするかどうかをチェックするwatchdogは、サーバーをすばやく釘付けします。

強く流れる-3日間で7ギグ。 以前は動作モードでしたが、1ギガ以上のギグは必要ありませんでした(再起動せずに2週間起動しました)。







循環リンクまたはコンテナからのデータは削除されないと考えられていました。

さて、私は古き良きGoogleパフォーマンスツールを使用して、作業時にメモリのスナップショットを撮ることにしました。 ふむ 何らかの理由でubuntu amd64の下では、古いバージョンのみ。 また、アプリケーションが並列化されるとハングします(ただし、google perfツールはマルチスレッドアプリケーション用に特別に作成されています)。

デバッガーは、すべてのスレッドがスピンロックでハングしていることを示します。



最新バージョンにアップグレードすることにしましたが、サイトからバージョンをコンパイルしたくありませんでした。 packages.debian.orgでパッケージを見つけました-驚くべきことに、すべてが問題なくインストールされました。

ただし、デーモンのマルチスレッドモードに入ると、再びフリーズします。

また、デーモン自体は15〜20分間ロードされます-実稼働からベースを取得し、大量のデータがあるためです。



デバッグ用の優れたアロケーターを探しました-必要なもの(google perf tools-ぶら下げないヒープpeofiler)がありませんでした。

おそらく、valgrind.memcheckには、プログラムの最後ではなく、途中でメモリ状態をダンプするキーがいくつかあるのでしょうか? いや しかし... valgrind.massifがあります-これを扱っています。 やった!



データベースの無慈悲なデータのクリア(少なくとも負荷テストは機能しますが、実際のゲームと少なくともいくつかの有効なデータが必要です)で、valgrind.massifを選び始めました。

私はそれを始めました-負荷テストを実行しました-すべてが機能しますが、何も流れません。 とても興味深い。

一般的に、ツールは私に何の答えも与えませんでした-おそらく、合成負荷はメモリリークを伴うエラーを引き起こしませんでした。 モスクをオンにする必要があります;)

残念ながら、最後の安定した注入以来、多くのコードが変更されており、私は非難しています:コード全体のほぼ半分に影響を与えるリファクタリングを行いました;)



私はzamampiのメモリについて考えて、そこに何があるか見てみましたが、7ギグのファイルを理解したくありませんでした。 そして-クレイジーなアイデアが生まれました-OSとデーモンの内部監視の両方から収集できる、デーモンに関する統計(クラスター内に3つある現在のデーモンの利点)を分析しました。



かなりの偶然に、リークしたメモリの量と同じタイプの実行されたコマンドの数の間の割合を見ました。 チームは古かったのですが、この土砂降りで私たちはもっと積極的に使用し始めたことを思い出しました。 計算機で割合を確認しました(シェルのpython;)-すべてが一致しています。 このクリーチャーは記憶を食べます。



全体的な問題は、同様のコマンドが請求のみに使用され、負荷テストがなかったことです。 そして最近、最初のコマンドと同様の機能を使用する同様のコマンドを作成しましたが、それは何回も実行されます。 ソーシャルネットワークでのみ使用され、負荷テストにも追加されていません。 これはとても悪い状況です。



このコマンドを負荷テストに追加しました-彼は10秒でラップトップのメモリの50%を食べました。 そして、それは技術的な問題です-私はmassifを使用しませんでした-コードを読みました-循環リンクが作成されない可能性がある場所を見つけました-ポリシーをStrongからWeakに変更しました-それを殺してテストを実行しました



さて、私は殺された日からデバッグするためにどんな結論を引き出しましたか? 実際、ここに:

  1. メモリリークのテストをより頻繁に実行する必要があります。
  2. リークが小さい場合でも(将来、コードがより積極的に使用されるようになる可能性があります)、小さなリークは深刻な頭痛になります
  3. 本番に似ているが、データが少ない代表的な機能ベースが必要です。 これがないと、メモリデバッガーでのデバッグは事実上不可能になります。
  4. 繰り返しますが、ベアポインターがないことでリークがないことを保証できないと確信しました(これはjavaとc#の両方に適用され、C ++でスマートポインターを使用する場合)
  5. 何も役に立たないとき-チャンスはすべてを解決することができます
  6. 事故はランダムではありません©=)-統計のいくつかの規則性を探すことなく、私はそれらを見つけませんでしたが、何かを見つけることを望んでいませんでした



All Articles