我的系统内存很小,1.5GB。我有一个C ++程序,调用特定方法大约300次。这个方法使用2个映射(每次都清除它们),我想知道在这个方法的某些调用中是否有可能堆栈溢出而程序失败。如果我输入小数据(因此方法被调用30次),程序运行正常。但现在它引发了SIGSEGV错误。我试图解决这个问题大约3天没有运气,我试过的每个解决方案都失败了。
我发现了SIGSEGV的一些原因,但没有任何帮助 What is SIGSEGV run time error in C++?
好的,这是代码。 我有2个实例,其中包含一些关键字功能及其分数
我想获得他们的eucleidian距离,这意味着我必须为每个实例保存所有关键字,然后找到第一个关键字与第二个关键字的差异,然后找到其余的差异第二个例子。我想要的是在迭代第一个地图时,能够从第二个地图中删除元素。由于我们有两个消息集合,因此多次调用以下方法,并将来自第一个消息集合的每条消息与来自第二个消息集合的每条消息进行比较。
我有这个代码,但它突然停止了,虽然我检查它工作了几秒钟,我放在一些地方多个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);
}
答案 0 :(得分:6)
如果malloc
失败并因此返回NULL
,它确实会导致SIGSEGV,假设程序没有正确处理该失败。但是,如果内存很低,你的系统很可能会开始使用大量内存来杀死进程(如果你感兴趣的话,实际的逻辑会更复杂,谷歌可以用“oom killer”)。
很可能你的程序中只有一个错误。解决这个问题的一个好方法是使用内存调试器(如valgrind
)来查看是否访问了无效的内存位置。
答案 1 :(得分:1)
一种可能的解释是程序在释放后访问动态分配的对象。如果对象足够小,则内存分配器会将内存保留在下一次分配中,并且释放后的访问是无害的。如果对象很大,则内存分配器会取消用于保存对象的页面,而free之后的访问会导致SIGSEGV。
几乎可以肯定的是,无论SIGSEGV发生的基本机制如何,代码中都存在一个错误,它是因果链的关键部分。
答案 2 :(得分:0)
1.5GB并不是那么小。一般来说,你可以做1.5GB。如果300次迭代耗尽1.5GB(假设OS内核使用0.5GB等),则每次迭代需要使用大约32MB。这是相当多的内存,所以,我的猜测是你的代码实际上使用了很多内存,或者你的代码包含某种类型的泄漏。更有可能是后者。我曾经使用过少于64KB的机器,而我的第一台PC有8MB的RAM,当时我认为很多。
答案 3 :(得分:0)
不,如果系统内存不足,此代码无法导致段错误。 map allocation使用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类上。它可能不是内存不足,应该是缓冲区溢出,可以通过调试器确认。
答案 4 :(得分:0)
如上所述,最可能的原因是内存分配不良或内存泄漏。检查缓冲区溢出,或者在释放资源后尝试访问资源。