2

私のシステムRAMは小さく、1.5GBです。特定のメソッドを約300回呼び出すC++プログラムがあります。このメソッドは2つのマップを使用し(それらは毎回クリアされます)、このメソッドの呼び出しの一部でスタックがオーバーフローしてプログラムが失敗する可能性があるかどうかを知りたいです。小さなデータを入れると(メソッドが30回呼び出されるように)、プログラムは正常に実行されます。しかし、今ではSIGSEGVエラーが発生します。私はこれを約3日間修正しようとしていますが、運が悪かったので、試したすべての解決策が失敗しました。

以下でSIGSEGVの原因をいくつか見つけましたが、何も 役に立ちませんでした。C++でのSIGSEGVランタイムエラーとは何ですか。

わかりました、ここにコードがあります。いくつかのキーワードを含む2つのインスタンスがあります-機能とそのスコア

彼らのユークレディアン距離を取得したいのですが、これは、各インスタンスのすべてのキーワードを保存してから、最初のキーワードと2番目のキーワードのdiffを見つけてから、残りの2番目のキーワードのdiffを見つける必要があることを意味します。実例。私が欲しいのは、最初のマップを繰り返しながら、2番目のマップから要素を削除できるようにすることです。次のメソッドは、2つのメッセージコレクションがあるため複数回呼び出され、最初のメソッドのすべてのメッセージが2番目のメッセージのすべてのメッセージと比較されます。

私はこのコードを持っていますが、いくつかの場所に置いた複数のcoutで数秒間動作していることを確認しましたが、突然停止します

これは大学のタスクのためのものであるため、ブーストとそれらすべてのトリックを使用することはできません。しかし、私は自分が抱えている問題を回避する方法を知りたいと思います。

float KNNClassifier::distance(const Instance& inst1, const Instance& inst2) {   
map<string,unsigned> feat1;
map<string,unsigned> feat2;
for (unsigned i=0; i<inst1.getNumberOfFeatures(); i++) {
  feat1[inst1.getFeature(i)]=i;
}
for (unsigned i=0; i<inst2.getNumberOfFeatures(); i++) {
  feat2[inst2.getFeature(i)]=i;
}
float dist=0;

map<string,unsigned>::iterator it;
for (it=feat1.begin(); it!=feat1.end(); it++) {
  if (feat2.find(it->first)!=feat2.end()) {//if and only if it exists in inst2
    dist+=pow( (double) inst1.getScore(it->second) - inst2.getScore(feat2[it->first]) , 2.0);
    feat2.erase(it->first);
  }
  else {
    dist+=pow( (double) inst1.getScore(it->second) , 2.0);
  }
}

for (it=feat2.begin(); it!=feat2.end(); it++) {//for the remaining words
  dist+=pow( (double) inst2.getScore(it->second) , 2.0);
}
feat1.clear(); feat2.clear(); //ka8arizoume ta map gia thn epomenh xrhsh
return sqrt(dist);    
}

また、何かを削除する必要がないようにこのアイデアを試しましたが、突然停止します。

float KNNClassifier::distance(const Instance& inst1, const Instance& inst2) {
map<string,unsigned> feat1;
map<string,unsigned> feat2;
map<string,bool> exists;
for (unsigned i=0; i<inst1.getNumberOfFeatures(); i++) {
  feat1[inst1.getFeature(i)]=i;
}
for (unsigned i=0; i<inst2.getNumberOfFeatures(); i++) {
  feat2[inst2.getFeature(i)]=i;
  exists[inst2.getFeature(i)]=false;
  if (feat1.find(inst2.getFeature(i))!=feat1.end()) {
    exists[inst2.getFeature(i)]=true;
  }
}
float dist=0;
map<string,unsigned>::iterator it;
for (it=feat1.begin(); it!=feat1.end(); it++) {
  if (feat2.find(it->first)!=feat2.end()) {
    dist+=pow( (double) inst1.getScore(it->second) - inst2.getScore(feat2[it->first]) ,      2.0);
  }
  else {
    dist+=pow( (double) inst1.getScore(it->second) , 2.0);
  }
}

for (it=feat2.begin(); it!=feat2.end(); it++) {
  if(it->second==false){//if it is true, it means the diff was done in the previous iteration
    dist+=pow( (double) inst2.getScore(it->second) , 2.0);
  }
}

feat1.clear(); feat2.clear(); exists.clear();
return sqrt(dist);
}
4

5 に答える 5

6

malloc失敗して戻ってきた場合NULL、プログラムがその失敗を適切に処理しないと仮定すると、実際にSIGSEGVにつながる可能性があります。ただし、メモリが少なすぎると、システムが大量のメモリを使用してプロセスを強制終了し始める可能性が高くなります(実際のロジックはより複雑です。興味がある場合は、「oomkiller」をグーグルで検索してください)。

プログラムに単にバグがある可能性があります。valgrindこれを理解する良い方法は、無効なメモリ位置にアクセスするかどうかを確認するなどのメモリデバッガを使用することです。

于 2012-12-29T19:24:55.560 に答える
1

考えられる説明の 1 つは、プログラムが動的に割り当てられたオブジェクトを解放した後にアクセスすることです。オブジェクトが十分に小さい場合、メモリ アロケータは次の割り当てのためにメモリを保持し、解放後のアクセスは無害です。オブジェクトが大きい場合、メモリ アロケータはオブジェクトを保持するために使用されるページのマップを解除し、解放後のアクセスによって SIGSEGV が発生します。

SIGSEGV が発生する根本的なメカニズムに関係なく、原因連鎖の重要な部分であるコードのどこかにバグがあることはほぼ確実です。

于 2012-12-29T20:12:28.547 に答える
0

1.5GBはそれほど小さくありません。一般的に1.5GBで多くのことができます。300回の反復で1.5GBを使用する場合(たとえば、OSカーネルで0.5GBが使用される場合など)、反復ごとに約32MBを使用する必要があります。これはかなりのメモリであるため、コードが実際に大量のメモリを使用しているか、コードに何らかのリークが含まれていると思います。後者の可能性が高いです。私は64KB未満のマシンで作業しましたが、最初のPCには8MBのRAMが搭載されていましたが、当時はそれがかなりの量と見なされていました。

于 2012-12-29T19:54:52.173 に答える
0

いいえ、システムがメモリ不足になった場合、このコードは segfault を引き起こすことができません。マップ割り当ては、割り当てにスタックを使用しない new 演算子を使用します。ヒープを使用し、メモリが使い果たされた場合は bad_alloc 例外をスローし、無効なメモリ アクセスが発生する前に中止します。

    $ cat crazyalloc.cc
    int main(void)
    {
            while(1) {
                    new int[100000000];
            }

            return 0;
    }
    $ ./crazyalloc
    terminate called after throwing an instance of 'std::bad_alloc'
      what():  std::bad_alloc
    Aborted (core dumped)

別の実装でもクラッシュするという事実は、問題がこのコードにないことを示しています。

問題は代わりにインスタンス クラスにあります。おそらくメモリ不足ではなく、デバッガで確認できるバッファオーバーフローのはずです。

于 2014-12-08T21:14:39.443 に答える