Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/150.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 为什么会抛出std::bad_alloc?_C++_Memory Management_Vector_Mapreduce_Bad Alloc - Fatal编程技术网

C++ 为什么会抛出std::bad_alloc?

C++ 为什么会抛出std::bad_alloc?,c++,memory-management,vector,mapreduce,bad-alloc,C++,Memory Management,Vector,Mapreduce,Bad Alloc,我正在实施一个map/reduce并行项目。然而,使用一个1GB的输入文件,例如,对于一个单词计数玩具,只有一个映射器(映射整个文件),我收到一个std::bad_alloc异常。不幸的是,这只发生在远程Xeon Phi上(具有较小的RAM),因此没有深入的调试 但是,内存被占用在两个位置:当映射程序在char*中读取(存储)整个文件时: void getNextKeyValue() { key = pos;//int value = new char[file_size];//

我正在实施一个map/reduce并行项目。然而,使用一个1GB的输入文件,例如,对于一个单词计数玩具,只有一个映射器(映射整个文件),我收到一个
std::bad_alloc
异常。不幸的是,这只发生在远程Xeon Phi上(具有较小的RAM),因此没有深入的调试

但是,内存被占用在两个位置:当映射程序在
char*
中读取(存储)整个文件时:

void getNextKeyValue() {
    key = pos;//int
    value = new char[file_size];//file_size only with 1 mapper
    ssize_t result = pread(fd, value, file_size, pos);
    assert(result == ( file_size ) );
    morePairs = false;
}
当调用
map
函数并在
向量
中存储一系列
时,另一个函数作为map的结果:

地图功能:

std::function<void(int key, char *value,MapResult<int,char*,char*,int> *result)> map_func = [](int key,char *value,MapResult<int,char*,char*,int> *result) {
    const char delimit[]=" \t\r\n\v\f";
    char *token , *save;
    token = strtok_r(value, delimit, &save);
    while (token != NULL){
        result->emit(token,1);
        token = strtok_r (NULL,delimit, &save);
    }
};
注意:通常
emit
中的
key
value
都是基于模板的,但为了清晰起见,我在本例中省略了它们

首先,我认为抛出
std::bad_alloc
是因为
char*value
(需要1GB),但异常是在测试
cout
消息后抛出的,该消息放置在
分配之后(因此这不是问题)

从我所读到的关于strtok实现的
char*
的内容来看,原始的
char*
被修改(在每个令牌的末尾添加
\0
),因此没有分配额外的内存

唯一剩下的可能性是
向量
占用的空间,但我无法计算它的空间(请帮助我)。假设平均字长为5个字符,我们应该有~2*10^8个单词

更新时间: 不幸的是,预先计算字数,然后调用
resize()
,以消除未使用的向量内存是不可行的,原因有两个:

  • 这将大大降低性能。不调用
    emit
    并且只计算280MB文件的字数,执行总时间1329ms需要1242ms(第一次读取文件时约5000s)
  • 使用该解决方案时,最终用户在编写MAP函数时应该深入考虑内存使用,这通常不会发生在像Hadoop之类的经典MAP/RADION框架中。

  • 问题不在于
    向量所使用的空间,而是向量以前在容量较小时所使用的所有空间。除非在向量上调用
    reserve
    ,否则在推送第一个元素时,它将开始为空并分配少量空间(通常足够容纳一个元素)。在以后的推送过程中,如果没有分配足够的剩余空间,它将分配更多空间(当前大小的1.5倍或2倍)。这意味着您需要足够的空闲内存来存储较小的和较大的内存。因为释放的内存块组合起来仍然不足以满足下一个更大的请求量,所以可能会有很多可用但未使用的内存


    您应该调用
    res.reserve(/*适当的大尺寸*/)
    ,或者将容器切换到
    deque
    ,虽然它最终需要更多的空间,但不需要随着其增长进行重新分配。要获得要保留的大小,您可以遍历文件一次,查看其中有多少单词,为它们保留空间,然后再次遍历并保存单词。

    您是否尝试使用调试器查看异常抛出的位置?正如我在问题中所说,我无法调试,因为我正在远程Xeon Phi上启动程序。回答了更新问题
        void emit(char* key, int value) {
            res.push_back(pair<char*,int>(key,value));
        }
        ...
        private:
        vector<pair<char*,int>> res;