C++ 为什么会抛出std::bad_alloc?
我正在实施一个map/reduce并行项目。然而,使用一个1GB的输入文件,例如,对于一个单词计数玩具,只有一个映射器(映射整个文件),我收到一个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];//
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)问题不在于
向量所使用的空间,而是向量以前在容量较小时所使用的所有空间。除非在向量上调用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;