微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

std::string::append 使用“std::bad_alloc”使程序崩溃

如何解决std::string::append 使用“std::bad_alloc”使程序崩溃

我有一个文本文件,其中包含与名称、位置和高度相关的数据列表。我的程序将此数据解析为矢量地图,然后使用此数据使用 boost::property_tree 构造一个 xml 文件。文本文件大约有 3500 行,程序始终在第 1773 行崩溃:

terminate called after throwing an instance of 'std::bad_alloc'
  what():  std::bad_alloc
Aborted (core dumped)

起初我以为可能已达到大小限制,但阅读 std::string 表明目标计算机应该能够分配所需的大小。无论如何,我决定用 std::string::size,std::string::length,std::string::capacity,std::string::max_size 进行测试,它们(分别)显示

...
...
6572094845  6572094845 6626476032 9223372036854775807
6579537815  6579537815 6626476032 9223372036854775807
6586984998  6586984998 6626476032 9223372036854775807
6594436394  6594436394 6626476032 9223372036854775807
6601892003  6601892003 6626476032 9223372036854775807
6609351825  6609351825 6626476032 9223372036854775807
6616815856  6616815856 6626476032 9223372036854775807
6624284100  6624284100 6626476032 9223372036854775807

std::string::capacity 被视为增加一次 std::string::length == std::string::capacity

编译调试后的gdb bt:

(gdb) bt
#0  __GI_raise (sig=sig@entry=6) at ../sysdeps/unix/sysv/linux/raise.c:51
#1  0x00007fd67037e921 in __GI_abort () at abort.c:79
#2  0x00007fd6709d3957 in ?? () from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
#3  0x00007fd6709d9ae6 in ?? () from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
#4  0x00007fd6709d9b21 in std::terminate() () from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
#5  0x00007fd6709d9d54 in __cxa_throw () from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
#6  0x00007fd6709da2dc in operator new(unsigned long) () from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
#7  0x00007fd670a6bb8b in std::__cxx11::basic_string<char,std::char_traits<char>,std::allocator<char> >::_M_mutate(unsigned long,unsigned long,char const*,unsigned long) () from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
#8  0x00007fd670a6d133 in std::__cxx11::basic_string<char,std::allocator<char> >::_M_append(char const*,unsigned long) () from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
#9  0x000056104c176f3a in main (argc=1,argv=0x7ffc0af8b9a8) at /home/code/hello_world/createWorld.cpp:224

正在读取的文本文件中的示例行:

713.258 235.418 ABCD1234567     2898

代码

int main(int argc,char **argv)
{
    CreateWorld *newWorld = new CreateWorld();
    lastModelsParser *lastModels = new lastModelsParser();
    
    /*
      Code here reads creates ifs for xml data,then reads xml successfully into a ptree
    */

    vector<lastModelsParser::lastModel> _lastModels;

    _lastModels = lastModels->getlastModels();

    uint16_t lastModelsEntry = 0;
    std::string newModelString;

    for(auto i:_lastModels){
        ptNewModel = newWorld->modelModifier(ptModel,_lastModels.at(lastModelsEntry).pX,_lastModels.at(lastModelsEntry).pY,_lastModels.at(lastModelsEntry).name,_lastModels.at(lastModelsEntry).height);

        boost::property_tree::xml_parser::write_xml_element(modelOSS,ptNewModel.front().first,ptNewModel.back().second,1,xml_settings);
        
        newModelString.append(modelOSS.str());              // CRASHES HERE 
 
        lastModelsEntry++;        
    }

    // append to world.xml
    boost::property_tree::write_xml(worldOSS,ptWorld,xml_settings);           // write xml data into Osstreams
    boost::property_tree::write_xml(modelOSS,ptModel,xml_settings);           // write xml data into Osstreams   
    size_t worldPos = worldOSS.str().find("</world>");

    std::string newWorldString = worldOSS.str().insert(worldPos,newModelString+"\n\t");

    newWorldFile << newWorldString ;
    

    delete(lastModels);
    delete(newWorld);

    return EXIT_SUCCESS;
}                                                                                                                                                                                                                           

编辑。 Valgrind 输出

  1. valgrind --tool=massif --massif-out-file=memleak.txt ./createNewWorld
heap_tree=detailed
n2: 6636657886 (heap allocation functions) malloc/new/new[],--alloc-fns,etc.
 n2: 6626476282 0x5160B89: std::__cxx11::basic_string<char,unsigned long) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.25)
  n2: 6626476282 0x5162131: std::__cxx11::basic_string<char,unsigned long) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.25)
   n0: 6626476033 0x149F38: main (in /home/code/hello_world/createNewWorld)
   n0: 249 in 2 places,all below massif's threshold (1.00%)
  n0: 0 in 2 places,all below massif's threshold (1.00%)
 n0: 10181604 in 18 places,all below massif's threshold (1.00%)
  1. valgrind --leak-check=full --show-leak-kinds=all --track-origins=yes --verbose --log-file=valgrind-out_1.txt ./createNewWorld
...
--4758-- memcheck GC: 1000 nodes,0 survivors (0.0%)
--4758-- memcheck GC: 1000 nodes,0 survivors (0.0%)
==4758== Warning: set address range perms: large range [0xee015040,0x1b37d5041) (undefined)

解决方法

std::string::max_size 不是您的系统可以分配的最大字符串。鉴于无限的连续内存空间,它只是 std::string 类本身可以表示的最大字符串。

您已经超过了 6GB,而且很有可能没有足够的内存来执行下一次重新分配所需的复制。您是否拥有该步骤所需的 13GB RAM,并且您配置的内核限制是否允许为单个进程分配那么多(甚至还没有承诺!)?

避免将所有内容存储在单个长字符串中,但要更早地对其进行分区/写出。然后重新分配只会导致内存使用量达到最大分配量的 2 倍,而不是当前总内存消耗量的 2 倍。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。