Linux C ++ программа падает с St9bad_alloc после того, как карта становится очень большой

Я запускаю программу на C ++, которая включает построение инвертированного индекса в 64-битной Red Hat Linux. Мой инвертированный индекс определяется как map<unsigned long long int, map<int,int> > invertID; и я получил эту ошибку, где он случайно падает, с what(): St9bad_alloc. Каждое время крушения отличается. Иногда я получал 100 000 000 ключей, и они все еще работают. Иногда около 8000000 ключей и это уже выкрикивает ошибку.

Погуглив, я обнаружил, что эта ошибка может исходить от new, но, взглянув на мой код, я не использую new Ключевое слово, но у меня есть такое распределение памяти с картой. Я продолжаю вставлять в пару ключ / значение в каждой итерации. Поэтому я решил поэкспериментировать с try catch заявление.

Фактически, вот критическая часть кода и вывода:

    map<unsigned long long int, map<int,int> >::iterator mainMapIt = invertID.find(ID);
if (mainMapIt != invertID.end()){
//if this ImageID key exists in InvID sub-map
map<int,int> M = mainMapIt->second; // THIS IS LINE 174.
map<int,int>::iterator subMapIt = M.find(imageID);
if (subMapIt != M.end()){
//increment the number of this ImageID key
++invertID[ID][imageID];
}
else{
//add ImageID key with value 1 into the InvertID
try{
invertID[ID][imageID] = 1;
++totalPushBack;
}catch (bad_alloc ba){
cout << "CAUGHT 1: invertID[" << ID << "][" << imageID << endl;
}
}
}
else{
//create the first empty map with the key as image ID with value 1 and put it in implicitly to the invertID
try{
invertID[ID][imageID] = 1;
}catch (bad_alloc ba){
cout << "CAUGHT 2: invertID[" << ID << "][" << imageID << endl;
}
}

Выход:

...
CAUGHT 2: invertID[21959247897][3856
CAUGHT 2: invertID[38022506156][3856
CAUGHT 2: invertID[29062506144][3856
terminate called after throwing an instance of 'std::bad_alloc'
what():  St9bad_alloc

Я вижу, что при попытке вставить новый ключ выдается ошибка. Тем не менее, я получил немного больше удивления, что St9bad_alloc все еще выбрасывается после того, как я закрываю часть вставки ключа try catch блок. Я сделал небольшой след и вот результат:

(gdb) backtrace
#0  0x000000344ac30265 in raise () from /lib64/libc.so.6
#1  0x000000344ac31d10 in abort () from /lib64/libc.so.6
#2  0x00000034510becb4 in __gnu_cxx::__verbose_terminate_handler() () from /usr/lib64/libstdc++.so.6
#3  0x00000034510bcdb6 in ?? () from /usr/lib64/libstdc++.so.6
#4  0x00000034510bcde3 in std::terminate() () from /usr/lib64/libstdc++.so.6
#5  0x00000034510bceca in __cxa_throw () from /usr/lib64/libstdc++.so.6
#6  0x00000034510bd1d9 in operator new(unsigned long) () from /usr/lib64/libstdc++.so.6
#7  0x0000000000406544 in __gnu_cxx::new_allocator<std::_Rb_tree_node<std::pair<int const, int> > >::allocate (
this=0x7fffffffdfc0, __n=1)
at /usr/lib/gcc/x86_64-redhat-linux/4.1.2/../../../../include/c++/4.1.2/ext/new_allocator.h:88
#8  0x0000000000406568 in std::_Rb_tree<int, std::pair<int const, int>, std::_Select1st<std::pair<int const, int> >, std::less<int>, std::allocator<std::pair<int const, int> > >::_M_get_node (this=0x7fffffffdfc0)
at /usr/lib/gcc/x86_64-redhat-linux/4.1.2/../../../../include/c++/4.1.2/bits/stl_tree.h:358
#9  0x0000000000406584 in std::_Rb_tree<int, std::pair<int const, int>, std::_Select1st<std::pair<int const, int> >, std::less<int>, std::allocator<std::pair<int const, int> > >::_M_create_node (this=0x7fffffffdfc0, __x=...)
at /usr/lib/gcc/x86_64-redhat-linux/4.1.2/../../../../include/c++/4.1.2/bits/stl_tree.h:367
#10 0x00000000004065e3 in std::_Rb_tree<int, std::pair<int const, int>, std::_Select1st<std::pair<int const, int> >, std::less<int>, std::allocator<std::pair<int const, int> > >::_M_clone_node (this=0x7fffffffdfc0, __x=0x21c082bd0)
at /usr/lib/gcc/x86_64-redhat-linux/4.1.2/../../../../include/c++/4.1.2/bits/stl_tree.h:381
#11 0x0000000000406634 in std::_Rb_tree<int, std::pair<int const, int>, std::_Select1st<std::pair<int const, int> >, std::less<int>, std::allocator<std::pair<int const, int> > >::_M_copy (this=0x7fffffffdfc0, __x=0x21c082bd0, __p=0x7fffffffdfc8)
at /usr/lib/gcc/x86_64-redhat-linux/4.1.2/../../../../include/c++/4.1.2/bits/stl_tree.h:1226
#12 0x00000000004067e9 in std::_Rb_tree<int, std::pair<int const, int>, std::_Select1st<std::pair<int const, int> >, std::less<int>, std::allocator<std::pair<int const, int> > >::_Rb_tree (this=0x7fffffffdfc0, __x=...)
at /usr/lib/gcc/x86_64-redhat-linux/4.1.2/../../../../include/c++/4.1.2/bits/stl_tree.h:570
#13 0x0000000000406885 in std::map<int, int, std::less<int>, std::allocator<std::pair<int const, int> > >::map (
this=0x7fffffffdfc0, __x=...) at /usr/lib/gcc/x86_64-redhat-linux/4.1.2/../../../../include/c++/4.1.2/bits/stl_map.h:175
#14 0x0000000000403039 in generateInvertID (pathToPF=0x6859a8 "/home/karl/c/000605.pf",
pathToC=0x38c139ed8 "/home/karl/c/000605.c", imageID=3856)
at InvertIndexGen.cpp:174
#15 0x0000000000403b46 in generateInvertIDForAllPFAndC () at InvertIndexGen.cpp:254
#16 0x0000000000403d0b in main (argc=1, argv=0x7fffffffe448) at InvertIndexGen.cpp:47
(gdb)

На # 14, InvertIndexGen.cpp: 174, в моем коде выше, это где он потерпел крах:

map<int,int> M = mainMapIt->second; // THIS IS LINE 174.

Кажется, когда я звоню ->secondнеобходимо создать копию соответствующей карты. Это должно быть причиной St9bad_alloc также.

Но в этом случае, что я могу сделать здесь? В конце концов, invertID.max_size() вернуть 18446744073709551615, и я использую только около 100 миллионов ключей. Я также вижу это из top, что моя программа использует только 10% памяти. (мы получили 128 ГБ ОЗУ)

Какие меры я должен использовать против этой ошибки? Я вижу, что некоторые из моих старших коллег делают то же самое, и они сообщают, что, когда их обратный индекс начинает расти, более 70-80% памяти в top, программа начинает выходить из строя. Но моя программа использует только 10%, так что здесь происходит? Что мы можем сделать, чтобы предотвратить эту ошибку?

РЕДАКТИРОВАТЬ: некоторые комментарии предлагают мне проверить с ulimitтак вот оно:

-bash-3.2$ ulimit -a
core file size          (blocks, -c) 0
data seg size           (kbytes, -d) unlimited
scheduling priority             (-e) 0
file size               (blocks, -f) unlimited
pending signals                 (-i) 1056768
max locked memory       (kbytes, -l) 32
max memory size         (kbytes, -m) unlimited
open files                      (-n) 1024
pipe size            (512 bytes, -p) 8
POSIX message queues     (bytes, -q) 819200
real-time priority              (-r) 0
stack size              (kbytes, -s) 10240
cpu time               (seconds, -t) unlimited
max user processes              (-u) 1056768
virtual memory          (kbytes, -v) unlimited
file locks                      (-x) unlimited

2

Решение

map<int,int> M = mainMapIt->second; // THIS IS LINE 174.

делает копию вашего второго.

map<int,int>& M = mainMapIt->second; // THIS IS LINE 174.

по крайней мере поможет избежать этой копии.

1

Другие решения

map<int,int> M = mainMapIt->second; // THIS IS LINE 174.
Эта строка вызовет ненужную копию карты и выделение памяти.
Изменение ссылки поможет.
map<int,int> & M = mainMapIt->second; // THIS IS LINE 174.

1