2

我的系统内存很小,1.5GB。我有一个调用特定方法大约 300 次的 C++ 程序。这个方法使用了 2 个映射(每次都被清除),我想知道在这个方法的某些调用中是否有可能堆栈溢出并且程序失败。如果我放入小数据(因此该方法被调用 30 次),程序运行良好。但现在它引发了 SIGSEGV 错误。我试图解决这个问题大约 3 天,但没有运气,我尝试的每个解决方案都失败了。

我在下面找到了 SIGSEGV 的一些原因,但没有任何帮助 什么是 C++ 中的 SIGSEGV 运行时错误?

好的,这里是代码。我有 2 个实例,其中包含一些关键字特征及其分数

我想得到他们的欧几里德距离,这意味着我必须保存每个实例的所有关键字,然后找到第一个关键字与第二个关键字的差异,然后找到第二个关键字的差异实例。我想要的是在迭代第一个地图时,能够从第二个地图中删除元素。由于我们有两个消息集合,因此多次调用以下方法,并且将来自第一个的每条消息与来自第二个的每条消息进行比较。

我有这段代码,但是它突然停止了,尽管我检查了它在某些地方放置了多个 cout 的情况下工作了几秒钟

请注意,这是针对大学任务的,因此我不能使用 boost 和所有这些技巧。但我想知道绕过我遇到的问题的方法。

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。但是,如果内存太低,您的系统更有可能开始使用大量内存杀死进程(实际逻辑更复杂,如果您有兴趣,请在谷歌搜索“oom killer”)。

很有可能您的程序中只有一个错误。解决这个问题的一个好方法是使用内存调试器,例如valgrind查看您是否访问了无效的内存位置。

于 2012-12-29T19:24:55.560 回答
1

一种可能的解释是您的程序在释放动态分配的对象后访问它。如果对象足够小,内存分配器会保留内存以供下次分配使用,释放后的访问是无害的。如果对象很大,内存分配器会取消映射用于保存对象的页面,并且释放后的访问会导致 SIGSEGV。

几乎可以肯定的是,无论 SIGSEGV 发生的底层机制如何,代码中的某个地方都存在一个错误,这是因果链的关键部分。

于 2012-12-29T20:12:28.547 回答
0

1.5GB 不算小。一般来说,你可以在 1.5GB 中做很多事情。对于 300 次迭代要使用 1.5GB(假设操作系统内核使用 0.5GB 等),每次迭代大约需要使用 32MB。那是相当多的内存,所以,我的猜测是您的代码实际上使用了很多内存,或者您的代码包含某种泄漏。更有可能是后者。我曾在小于 64KB 的机器上工作,而我的第一台 PC 有 8MB 的内存,这在当时被认为是很多。

于 2012-12-29T19:54:52.173 回答
0

不,如果系统内存不足,此代码无法导致段错误。map 分配使用 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)

替代实现也崩溃的事实暗示问题不在此代码中。

问题出在 Instance 类上。可能不是内存不足,应该是缓冲区溢出,可以用调试器确认。

于 2014-12-08T21:14:39.443 回答
0

如上所述,最可能的原因是内存分配错误或内存泄漏。检查缓冲区溢出,或者是否在释放资源后尝试访问它。

于 2015-02-17T17:35:21.080 回答