下面的测试用例在使用OpenMP时在“post MT section”消息之后的循环中耗尽32位机器上的内存(抛出std :: bad_alloc),但是,如果注释掉了#pragmas for OpenMP,代码运行完成正常,所以当内存在并行线程中分配时,它似乎没有正确释放,因此我们的内存不足。
问题是下面的内存分配和删除代码是否有问题,或者这是gcc v4.2.2或OpenMP中的错误?我也尝试过gcc v4.3并且失败了。
int main(int argc, char** argv)
{
std::cout << "start " << std::endl;
{
std::vector<std::vector<int*> > nts(100);
#pragma omp parallel
{
#pragma omp for
for(int begin = 0; begin < int(nts.size()); ++begin) {
for(int i = 0; i < 1000000; ++i) {
nts[begin].push_back(new int(5));
}
}
}
std::cout << " pre delete " << std::endl;
for(int begin = 0; begin < int(nts.size()); ++begin) {
for(int j = 0; j < nts[begin].size(); ++j) {
delete nts[begin][j];
}
}
}
std::cout << "post MT section" << std::endl;
{
std::vector<std::vector<int*> > nts(100);
int begin, i;
try {
for(begin = 0; begin < int(nts.size()); ++begin) {
for(i = 0; i < 2000000; ++i) {
nts[begin].push_back(new int(5));
}
}
} catch (std::bad_alloc &e) {
std::cout << e.what() << std::endl;
std::cout << "begin: " << begin << " i: " << i << std::endl;
throw;
}
std::cout << "pre delete 1" << std::endl;
for(int begin = 0; begin < int(nts.size()); ++begin) {
for(int j = 0; j < nts[begin].size(); ++j) {
delete nts[begin][j];
}
}
}
std::cout << "end of prog" << std::endl;
char c;
std::cin >> c;
return 0;
}
答案 0 :(得分:3)
将第一个OpenMP循环从1000000更改为2000000将导致相同的错误。这表明内存不足问题与OpenMP堆栈限制有关。
尝试使用
将OpenMP堆栈限制设置为bash中的unlimitulimit -s unlimited
您还可以更改OpenMP环境变量OMP_STACKSIZE并将其设置为100MB或更多。
更新1:我将第一个循环更改为
{
std::vector<std::vector<int*> > nts(100);
#pragma omp for schedule(static) ordered
for(int begin = 0; begin < int(nts.size()); ++begin) {
for(int i = 0; i < 2000000; ++i) {
nts[begin].push_back(new int(5));
}
}
std::cout << " pre delete " << std::endl;
for(int begin = 0; begin < int(nts.size()); ++begin) {
for(int j = 0; j < nts[begin].size(); ++j) {
delete nts[begin][j]
}
}
}
然后,我在主线程上的i = 1574803处出现内存错误。
更新2:如果您使用的是英特尔编译器,您可以在代码顶部添加以下内容,它将解决问题(假设您有足够的内存来承担额外的开销)。
std::cout << "Previous stack size " << kmp_get_stacksize_s() << std::endl;
kmp_set_stacksize_s(1000000000);
std::cout << "Now stack size " << kmp_get_stacksize_s() << std::endl;
更新3:为了完整性,如同其他成员所提到的,如果您正在执行一些数值计算,最好在一个 new float [1000000] 中预先分配所有内容,而不是使用OpenMP来执行1000000次分配。这也适用于分配对象。
答案 1 :(得分:3)
我发现这个问题在其他地方看不到OpenMP,只是使用pthreads。多线程时额外的内存消耗似乎是标准内存分配器的典型行为。通过切换到Hoard分配器,额外的内存消耗就会消失。
答案 2 :(得分:0)
为什么使用int*
作为内部向量成员?这非常浪费 - 对于每个sizeof(int)
条目,您有4个字节(严格vector
)数据和堆控制结构的2-3倍。尝试使用vector<int>
,看看它是否运行得更好。
我不是OpenMP专家,但这种用法在其不对称性方面似乎很奇怪 - 你在并行部分填充向量并用非并行代码清除它们。不能告诉你这是不是错了,但感觉'错了'。