Мой системный диск маленький, 1,5 ГБ. У меня есть программа на C ++, которая вызывает конкретный метод около 300 раз. Этот метод использует 2 карты (они очищаются каждый раз), и я хотел бы знать, возможно ли в некоторых вызовах этого метода переполнение стека и сбой программы. Если я поместил небольшие данные (так метод вызывается 30 раз), программа работает нормально. Но сейчас возникает ошибка SIGSEGV. Я пытаюсь исправить это в течение приблизительно 3 дней, и не повезло, каждое решение, которое я попробовал, не удалось.
Я нашел причину SIGSEGV ниже, но ничего не помогло
Что такое ошибка во время выполнения SIGSEGV в C ++?
Хорошо, вот код.
У меня есть 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);
}
Как упоминалось выше, наиболее вероятной причиной является неправильное распределение памяти или утечка памяти. Проверьте наличие переполнения буфера или попытайтесь получить доступ к ресурсу после его освобождения.
Если malloc
терпит неудачу и таким образом возвращается NULL
это действительно может привести к SIGSEGV, если программа неправильно обрабатывает этот сбой. Однако, если бы памяти было так мало, ваша система с большей вероятностью начала бы уничтожать процессы, используя много памяти (реальная логика более сложная, если вам интересно, поищите в Google «oom killer»).
Скорее всего, в вашей программе просто ошибка. Хороший способ понять это — использовать отладчик памяти, такой как valgrind
чтобы увидеть, если вы обращаетесь к недопустимым ячейкам памяти.
Одним из возможных объяснений является то, что ваша программа обращается к динамически размещаемому объекту после его освобождения. Если объект достаточно мал, распределитель памяти сохраняет память для следующего выделения, и доступ после освобождения безвреден. Если объект большой, распределитель памяти распаковывает страницы, используемые для хранения объекта, и доступ после освобождения вызывает SIGSEGV.
Совершенно очевидно, что независимо от базового механизма, с помощью которого происходит SIGSEGV, в коде есть ошибка, которая является ключевой частью причинной цепочки.
1,5 ГБ не так уж мало. Вы можете многое сделать в 1,5 ГБ в целом. Для 300 итераций, чтобы использовать 1,5 ГБ (скажем, 0,5 ГБ используется ядром ОС и т. Д.), Вам нужно использовать примерно 32 МБ на каждую итерацию. Это довольно много памяти, поэтому я предполагаю, что либо ваш код использует ОЧЕНЬ много памяти, либо ваш код содержит какую-то утечку. Скорее последнее. Я работал на компьютерах с объемом менее 64 КБ, и мой первый ПК имел 8 МБ оперативной памяти, и в то время это считалось МНОГО.
Нет, этот код не может вызвать сбой, если системе не хватает памяти. Карта размещения использует оператор 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. Вероятно, это не недостаток памяти, это должно быть переполнение буфера, что можно подтвердить с помощью отладчика.