【发布时间】:2016-04-04 01:24:55
【问题描述】:
我正在实施一个 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 函数并将一系列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;
注意:通常emit 中的key 和value 是基于模板的,但为了清楚起见,在本例中我省略了它们。
首先我认为std::bad_alloc 是因为char *value(占用1GB)而引发的,但是在value 分配之后放置了测试cout 消息后引发了异常(所以这不是问题)。
根据我所读到的关于strtok 实现的内容,原始的char* 被修改(在每个标记的末尾添加\0),因此没有分配额外的内存。
唯一剩下的可能性是vector<pair<char*,int>> 占用的空间,但我无法计算它的空间(请帮助我)。假设平均字长为 5 个字符,我们应该有 ~ 2*10^8 个字。
1201ProgramAlarm's answer 之后的更新:
不幸的是,预先计算字数然后调用resize() 以消除未使用的向量的内存是不可行的,原因有两个:
- 这会大大降低性能。如果不调用
emit并且仅计算 280MB 文件的字数,则在 1329 毫秒的总执行时间中需要 1242 毫秒(第一次读取文件时约为 5000 秒)。 - 使用此解决方案,最终用户在编写 map 函数时应深入考虑内存使用情况,这在 Hadoop 等经典 map/reduce 框架中通常不会发生。
【问题讨论】:
-
您是否尝试使用调试器查看异常是在哪里引发的?
-
正如我在问题中所说,我无法调试,因为我在远程 Xeon Phi 上启动程序。
标签: c++ memory-management vector mapreduce bad-alloc