SIGSEGV的原因会是系统内存不足吗?

Can the cause of SIGSEGV be the low ram of the system?

本文关键字:系统 内存不足 SIGSEGV      更新时间:2023-10-16

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

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

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

我想要得到它们的欧几里德距离,这意味着我必须保存每个实例的所有关键字,然后找到第一个实例的关键字与第二个实例的关键字的差,然后找到第二个实例剩余部分的差。我想要的是在迭代第一个映射时,能够从第二个映射中删除元素。下面的方法被调用多次,因为我们有两个消息集合,来自第一个消息集合的每条消息都与来自第二个消息集合的每条消息进行比较。

我有这段代码,但是它突然停止了尽管我检查了它工作了几秒钟,有多个计数我在一些地方输入

注意,这是一个大学任务,所以我不能使用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);
}

如果malloc失败并因此返回NULL,它确实可以导致SIGSEGV,假设程序没有正确处理该失败。然而,如果内存很低,你的系统更有可能开始杀死使用大量内存的进程(实际的逻辑更复杂,如果你感兴趣,谷歌搜索"oom killer")。

很有可能你的程序中有一个bug。找出这一点的一个好方法是使用内存调试器,如valgrind,看看你是否访问无效的内存位置。

一个可能的解释是你的程序在释放一个动态分配的对象之后访问了它。如果对象足够小,内存分配器会为下一次分配保留内存,并且free之后的访问是无害的。如果对象很大,内存分配器将解映射用于保存该对象的页面,并且在free之后的访问将导致SIGSEGV。

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

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

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

不,如果系统内存不足,此代码无法导致段错误。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类上。它可能不是内存不足,它应该是缓冲区溢出,这可以通过调试器来确认。