new失敗問題の検索プロセス

5608 ワード

テスト部で問題を発見し、システム全体がしばらく走るとdaemonプログラムがクラッシュし、必ず現れるわけではありませんが、1日に何度も発生することができ、性能テストが続けられなくなりました.coreの情報を見るとnewが失敗しました.具体的なスタックは以下の通りです.
  (gdb) bt  #0  0x2acd25c1 in kill () from/lib/libc.so.6  #1  0x2adfc58d in pthread_kill () from/lib/libpthread.so.0  #2  0x2adfc90b in raise () from/lib/libpthread.so.0  #3  0x2acd2364 in raise () from/lib/libc.so.6  #4  0x2acd389b in abort () from/lib/libc.so.6  #5  0x2ac57b57 in __cxa_call_unexpected () from/usr/lib/libstdc++.so.5  #6  0x2ac57ba4 in std::terminate() () from/usr/lib/libstdc++.so.5  #7  0x2ac57d16 in __cxa_throw () from/usr/lib/libstdc++.so.5  #8  0x2ac57f02 in operator new(unsigned) () from/usr/lib/libstdc++.so.5  #9  0x2ac57fef in operator new[](unsigned) () from/usr/lib/libstdc++.so.5  #10 0x2abbfe43 in NSlab::alloc_buf(unsigned*) (pSize=0x7ffff300) at Nslab.cpp:199
newが失敗する場合がありますが、私たちのシステム全体ではこのような状況を処理していません.私たちのほとんどのメモリは決まっています.どのようなプラットフォームモデルがどのような同時接続をサポートできるか、これらは予算がよく、newが失敗することはありません.
最初はメモリの漏洩が疑われたが、coreファイル全体を見ると100 M以上しかなく、メモリの漏洩が発生する可能性はないはずだ.別の発生は偶然かもしれませんが、走り続けるうちに他のプログラムも崩壊することに気づきました.newが失敗したためで、他のプログラムがメモリ漏れする可能性はありません.安定したプログラムが多いので、この可能性はありません.
2つ目のステップは、システムに本当にメモリがないかどうかを疑い始めます.システムのSIGABRT信号をキャプチャし、信号処理関数にシステムの状態をすべて印刷しました.ps、top、free、/proc/meminfo、/proc/slabinfoなどが含まれています.しかし、クラッシュ時にはプロセスが100 M以上のメモリしか消費されていないのを見ただけで、システムfreeのメモリは2 G以上あり、残りの情報もシステムメモリが絶対に十分であることを証明することができます.システムメモリが原因ではないようですが、もしそうであれば、問題も検索し続ける必要はありません.メモリがあるときも失敗しているので、これは必ず調べていきます.
第3歩はシステムを疑い始め、newは標準ライブラリが提供しているが、このとき私たちのカーネルバージョンは2.4.32から2.4.35.4に移行し、何か不一致が原因ではないか.downloadは1つのstdc++ライブラリを実現して、newの実現は実はCライブラリの中のmallocを呼び出して、GNUの上で1つのマッチングバージョンのCライブラリを下りて、mallocの中でいくつかのログを印刷して、DEBUGバージョンのcライブラリで開いて問題を探したいと思って、Cライブラリのコンパイルの過程は確かにとても複雑で面倒で、編纂が終わってからシステムの上に置くつもりで、直接前のlibcライブラリを上書きしないために、私はmvを使って前のlibcを名前を変えました.libcが変更されると、すべてのコマンドが使用できなくなり、libcライブラリが見つかりません.唯一使用可能なコマンドはcdが1つしか残っていないようです.ddもlibcライブラリに頼っています.仕方なくディスクを掛けて、やっとlibcをコピーして、よし、ほっとして、再起動するしかありませんが、libcを交換した後のシステムは起動できません.一日中振り回されて、人は振り回されて気絶して、それを起こすことができませんでした.
第四歩、libcを交換してしばらく通じない以上、方向を変えます.mallocの実装はオペレーティングシステムのbrkを呼び出して実現されていますが、この中には何か猫が飽きていますか?sysを見てみましたbrkのコードは、失敗した点が多く返されます.どうせカーネルコードを修正したり、カーネルを交換したりするのは慣れているので、戻るたびにログを印刷したり、カーネルを交換したりします.やっと収穫があって、sys_で発見しましたbrkでdo_を呼び出すbrk()の時に失敗して、更に詳しく追跡して、do_を発見しますbrk()では、次の文によってENOMEMが返されます.
    /* Check against address space limits *after* clearing old maps... */
      if ((mm->total_vm << PAGE_SHIFT) + len > current->rlim[RLIMIT_AS].rlim_cur) 
return -ENOMEM;

この文は、プロセスが割り当てるメモリが割り当てられる最大メモリを超えていることを示します.current->rlim[RLIMIT_AS].rlim_Curの値が印刷されたのは134217728、つまり128 MBで、その時に前のcoreファイルのサイズを振り返ってみると、やはり大きくなく、ちょうど134217728バイトでした.この値はsetrlimitでパラメータRLIMIT_を取得できます.ASで設定されているのは、プログラムコードを見て、RLIMIT_を設定したことがあるだけです.COREのいくつかの属性は、RLIMIT_を設定したことがありません.ASの属性.誰が設定したの?ここでテストしたらRLIMITをもう一度AS属性は4 Gに設定すればよいが,問題の根源が見つからない場合,潜在的な問題があるかどうかは分からない.
ステップ5では、誰がRLIMITを設定したのかを探し始めます.AS属性?システム全体のコードを検索しましたRLIMIT_ASもsetrlimitも、見つからなかった.まさかプログラム実行中に修正されたのですか?検証のため、プログラム起動点とSIGABRT信号処理関数の両方でgetrlimitでRLIMIT_を取得します.ASの属性を印刷して、手動で実行してみると、起動時に印刷された値は4294967296、すなわち4 Gであったが、プログラムがクラッシュした場合、印刷された値は128 MBであり、無言であった.途中でこの値が変更されたかどうかを確認するためsys_brkにメモリを割り当てると、currentのプロセス名とそのプロセスのRLIMIT_AS値印刷、いつRLIMIT_を知りたいですASの値は変更されます.何度か実験してみたが、推論に合わない点が発見され、この値はずっと修正されていないが、プログラムが起動したときは4 Gだったり、128 Mだったりして、128 Mに出会ったときにプレッシャーをかけるとnewが失敗し、再び無言に陥った.
第6段階では、上記の作業手順で印刷されたログを見て退屈になる.同時にnew失敗の現象を繰り返している.いくつかのシステムパラメータを修正すると、new失敗の可能性が50%以上に向上することが分かったからだ.これらのログをじっと見つめていたが、突然ひらめいて、web操作ページから「有効化」をクリックしてプログラムを起動した場合、RLIMIT_ASの値は128 Mですが、自分がshellコンソールでコマンドを叩いてプログラムを有効にした場合、RLIMIT_ASの値は4 Gで、新大陸を発見したのと同じで、CGI自身がRLIMITを設置したのではないでしょうか.ASは128 Mであり、次にexeclが有効にするプログラムを呼び出すのも128 Mであり、この属性は親プロセスから継承される.検証してみると、やはり、CGIイネーブラはnewの失敗でクラッシュし、CGIのRLIMIT_AS属性値も128 Mである.しかし、CGIコード自体にも128 Mの制限は設けられておらず、boa(私たちが使っているHTTPサーバはboa)のコードに制限されているのではないでしょうか.ちょうど私たちのboaは他の部門から持ってきたので、実行可能なファイルだけで、ソースコードがないので、これまですべてのソース検索がコードを検索できなかった理由も説明できます.問題は明らかになりますが、boaのソースコードを手に入れたとき、残念ながらこの値は設定されていませんでしたが、boaを再起動するとboa印刷のRLIMIT_が見つかりました.AS値は確かに128 Mです.幽霊に会った.
第7段階、退屈な時、突然連想して、直接shellの中で直接boaを有効にするのも4 Gですか?テストしてみたら、やっぱり、boaに直接打ち込んで起動、RLIMIT_ASの値は4 Gで、以前boaを再起動したのは彼のスクリプト/etc/initだった.d/boa restartが有効になったので、すぐにスクリプトを見て、daemonでboaを有効にする前に、「ulimit-m 131072」という言葉が入っていて、削除して、すべて正常に戻りました.
これで明らかになったのは、時間的に見ると、これまでのN個のモジュールをまたいで3週間追跡してやっと調べた1つのBUGに比べて、この問題は3日間しか調べられなかったが、追跡過程は起伏し、以前は私がこの問題を調べたわけではなく、プロジェクトグループ内の他の人で、システムとメモリがあり、newが失敗したことを調べたとき、彼らは調べないことを放棄し、コードの問題ではないと肯定した.探し続けることができなかった時に捨ててくれました.
BUGの経験を调べるのはやはり注意深くて広い考えで、注意深いのはもちろんいくつかの他の人が気づかない地方に関心を持って、通常1つの小さい発见はすぐに问题を解决することができて、私はある人が半日探してまだ问题の原因を位置づけていないことを见て、一部の人は现场を狙って、いくつかの情报を见て、すぐに考えを见て、もちろん考えの広い能力はあなたの知识のシステムの上で创立しました.また、バグを調べる際にも、自分の知識を蓄積することに注意しましょう.