我正在实施map / reduce并行项目。但是,使用(或多或少)1GB的输入文件,对于字数统计玩具示例,只有一个映射器(映射整个文件),我会收到std::bad_alloc
异常。不幸的是,这只发生在远程Xeon Phi(RAM较小)上,所以没有深度调试。
但是,内存占用了2个位置:当映射器在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
函数时的另一个函数和一系列pair<char*,int>
作为地图的结果存储在vector
内:
地图功能:
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
实施(以及地图'结果生成):
void emit(char* key, int value) {
res.push_back(pair<char*,int>(key,value));
}
...
private:
vector<pair<char*,int>> res;
注意: key
中的value
和emit
通常都是基于模板的,但在此示例中我省略了它们。
首先,我认为由于std::bad_alloc
(需要1GB)而抛出char *value
,但在{{1}之后放置测试cout
消息后抛出异常分配(这不是问题)。
从我读到的关于value
实现的内容中,原始的strtok
被修改(在每个令牌的末尾添加char*
),因此没有分配额外的内存。
唯一剩下的可能性是\0
占用的空间,但我无法计算它的空间(请帮我解决)。假设平均字长为5个字符,我们应该有~2 * 10 ^ 8个字。
1201ProgramAlarm's answer之后更新
不幸的是,预先计算单词的数量,然后调用vector<pair<char*,int>>
以消除未使用的向量的内存是不可行的,原因有两个:
resize()
并仅计算280MB文件的字数,则总执行时间超过1329ms需要1242ms(第一次读取文件时需要大约5000s)。答案 0 :(得分:0)
问题不在于vector
所使用的空间,它是载体在容量较小时以前使用的所有空间。除非你在向量上调用reserve
,否则当你按下第一个元素时,它会开始为空并分配少量空间(通常足够一个元素)。在以后的推送期间,如果没有足够的剩余空间分配,它将分配更多(当前大小的1.5倍或2倍)。这意味着你需要足够的可用内存用于较小的和较大的。因为释放的内存块在合并时仍然不足以满足下一个更大的请求量,可能会有很多空闲但未使用的内存。
你应该调用res.reserve(/*appropriate large size*/)
,或者将容器切换到deque
,虽然它最终需要更多空间,但随着它的增长,不需要重新分配。要获得保留的大小,您可以遍历文件一次以查看其中有多少单词,为它们预留空间,然后再次移动并保存单词。