0

私はこのかなり大きなネットワークシミュレーターをC++で書いています。私はそれらを開発している間、定期的に個々の部分をテストしてきました、そしてすべてをまとめた後、私がシミュレーターに課す負荷が大きすぎない限りそれはうまくいくようです(それはP2Pコンテンツ配信シミュレーターなので、より異なっています "内容」シミュレータが処理しなければならないより多くのデータ転送を紹介します)。シミュレートされているさまざまなコンテンツの数の特定のしきい値を超えると、数分間スムーズに実行された後、突然のSIGSEGVが発生します。メモリリークが発生し、最終的には大きくなりすぎて混乱していると思いましたが、しきい値を下回るパラメータでvalgrindを実行すると、問題なく終了しました。ただし、コンテンツ番号の重要な値を使用してvalgrindでプログラムを実行しようとすると、

==5987== Invalid read of size 8
==5987==    at 0x40524E: Scheduler::advanceClock() (Scheduler.cpp:38)
==5987==    by 0x45BA73: TestRun::execute() (TestRun.cpp:73)
==5987==    by 0x45522B: main (CDSim.cpp:131)
==5987==  Address 0x2e63bc70 is 0 bytes inside a block of size 32 free'd
==5987==    at 0x4C2A4BC: operator delete(void*) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==5987==    by 0x405487: Scheduler::advanceClock() (Scheduler.cpp:69)
==5987==    by 0x45BA73: TestRun::execute() (TestRun.cpp:73)
==5987==    by 0x45522B: main (CDSim.cpp:131)
==5987==
==5987== Invalid read of size 4
==5987==    at 0x40584E: Request::getSimTime() const (Event.hpp:45)
==5987==    by 0x40525C: Scheduler::advanceClock() (Scheduler.cpp:38)
==5987==    by 0x45BA73: TestRun::execute() (TestRun.cpp:73)
==5987==    by 0x45522B: main (CDSim.cpp:131)
==5987==  Address 0x2e63bc78 is 8 bytes inside a block of size 32 free'd
==5987==    at 0x4C2A4BC: operator delete(void*) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==5987==    by 0x405487: Scheduler::advanceClock() (Scheduler.cpp:69)
==5987==    by 0x45BA73: TestRun::execute() (TestRun.cpp:73)
==5987==    by 0x45522B: main (CDSim.cpp:131)
==5987==

コード全体を見ずに答えを出すのは難しいかもしれませんが、ここで何が起こっているのかについての「高レベルの」ヒントはありますか?正常に動作しているように見える関数が突然誤動作し始める理由がわかりません。多分私が行方不明になっている明らかな何かがありますか?

前のvalgrindログの有罪判決を受けた行はif (nextEvent->getSimTime() < this->getSimTime())、次のブロックにあります。

bool Scheduler::advanceClock() {
  if (pendingEvents.size() == 0) {
    std::cerr << "WARNING: Scheduler::advanceClock() - Empty event queue before "
        "reaching the termination event" << std::endl;
    return false;
  }
  const Event* nextEvent = pendingEvents.top();
  // Check that the event is not scheduled in the past
  if (nextEvent->getSimTime() < this->getSimTime()) {
    std::cerr << "Scheduler::advanceClock() - Event scheduled in the past!" << 
        std::endl;
    std::cerr << "Simulation time: " << this->getSimTime()
        << ", event time: " << nextEvent->getSimTime()
        << std::endl;
    exit(ERR_EVENT_IN_THE_PAST);
  }
  // Update the clock with the current event time (>= previous time)
  this->setSimTime(nextEvent->getSimTime());
  ...

ここで、pendingEventsはboost :: heap::binomial_heapです。

4

2 に答える 2

1

私はついに問題が何であるかを見つけました。イベントが完了し、リストから削除する必要がある場合、私のコードは次のようになりました。

...
// Data transfer completed, remove event from queue
// Notify the oracle, which will update the cache mapping and free resources
// in the topology
oracle->notifyCompletedFlow(nextEvent, this);
// Remove flow from top of the queue
pendingEvents.pop();
handleMap.erase(nextEvent);
delete nextEvent;
return true;

問題はoracle->notifyCompletedFlow()、スケジュールされたイベントの優先度を動的に更新するためにスケジューラーでいくつかのメソッドを呼び出したため(たとえば、ネットワークで使用可能な帯域幅の変更に対応するため)、pendingEvents.pop()場合によってはキューの先頭を削除するまでに別のイベントをポップして、削除されたnextEventをそこに残していました。オラクルを呼び出す前にキューをポップすることで、問題は解決しました。

より迅速な回答につながる可能性のあるコードの一部を省略してしまったことをお詫びします。私の間違いから学ぼうとします:)正しい方向に向けてくれてありがとう。

于 2012-06-27T12:25:42.380 に答える
0

スタックのようなもののようにconst Event* nextEvent = pendingEvents.top();見えるものかもしれません。pendingEventsあなたはこれを試すことができます:

  1. インストルメント(std :: cerr |ファイルへの出力と同じくらい簡単なトレースを追加することを意味します)メモリの割り当てと割り当て解除を行うコード(malloc / new、free / deleteを使用する場合)。
  2. デバッグツールとして、イベントにスマートポインターを使用してみてください。これにより、逆参照中にポインターの有効性がチェックされます(演算子->)。
于 2012-06-26T19:31:16.843 に答える