C++:OpenMP 并行循环内存泄漏

标签 c++ memory-leaks openmp armadillo

大家好, 我在 C++ 代码中使用 OpenMP 时遇到了相当严重的内存泄漏问题。我正在为一些地球物理计算编写一个库,它们非常耗时。我创建了一段简单的代码来给您一个想法(原始代码很长,希望对于解决方案来说不是必需的)。为了避免一遍又一遍地重写“相同”的代码行,我有一些模板,它们是通过使用指向方法函数的指针来指定的(就像我知道空间中的位置并且需要计算不同的数量一样)。我还使用“armadillo”( http://arma.sourceforge.net/ )库进行一些计算,但无论有没有它,问题仍然存在。

如果代码仅使用单线程运行,则不会出现任何问题。但随着时间的推移,使用 OpenMP(#pragma 指令)会导致内存泄漏。该程序实际上消耗了所有可用内存,然后崩溃。您可以使用我提供的代码重现该程序(只需将“迭代大小”从 5000 更改为更大的值)

我尝试用我自己的“ Armadillo vector ”替换“ Armadillo vector ”,但它似乎不会引起问题。我认为 Armadillo 不是问题。我运行了 valgrid memcheck 但不确定到底发生了什么(两种类型的“错误”):

149,520,000 bytes in 3,738 blocks are definitely lost in loss record 24 of 25
  in Openmp_class::generate_data(unsigned long) in $HOME/Programovanie/Ptr2memOpenMP/openmp_class.cpp:20
  1: operator new[](unsigned long) in /builddir/build/BUILD/valgrind-3.15.0/coregrind/m_replacemalloc/vg_replace_malloc.c:433
  2: Openmp_class::generate_data(unsigned long) in $HOME/Programovanie/Ptr2memOpenMP/openmp_class.cpp:20
  3: main._omp_fn.0 in $HOME/Programovanie/Ptr2memOpenMP/main.cpp:44
  4: /usr/lib64/libgomp.so.1.0.0
  5: start_thread in /usr/lib64/libpthread-2.29.so
  6: clone in /usr/lib64/libc-2.29.so

49,840,000 bytes in 1,246 blocks are definitely lost in loss record 22 of 25
  in Openmp_class::multiply_elements() in $HOME/Programovanie/Ptr2memOpenMP/openmp_class.cpp:90
  1: operator new[](unsigned long) in /builddir/build/BUILD/valgrind-3.15.0/coregrind/m_replacemalloc/vg_replace_malloc.c:433
  2: Openmp_class::multiply_elements() in $HOME/Programovanie/Ptr2memOpenMP/openmp_class.cpp:90
  3: main._omp_fn.0 in $HOME/Programovanie/Ptr2memOpenMP/main.cpp:45
  4: GOMP_parallel in /usr/lib64/libgomp.so.1.0.0
  5: main in $HOME/Programovanie/Ptr2memOpenMP/main.cpp:14

头文件:openmp_class.h

#ifndef OPENMP_CLASS_H
#define OPENMP_CLASS_H
#include <iomanip>
#include <iostream>
#include <cmath>
#include <armadillo>

using namespace std;

class Openmp_class
{
    double* xvec;
    double* yvec;

    size_t size;
public:
    Openmp_class();
    ~Openmp_class();

    void generate_data( size_t n );

    double add_element( size_t n );
    double substract_element( size_t n );

    arma::vec add_elements( size_t upto_n );
    arma::vec multiply_elements( size_t upto_n );

    double *multiply_elements();
};

#endif // OPENMP_CLASS_H

CPP文件openmp_class.cpp

#include "openmp_class.h"

Openmp_class::Openmp_class()
{

}

Openmp_class::~Openmp_class()
{
    this->xvec = nullptr;
    this->yvec = nullptr;

    delete [] this->xvec;
    delete [] this->yvec;
}

void Openmp_class::generate_data(size_t n)
{
    this->xvec = new double[n];
    this->yvec = new double[n];

    this->size = n;

    arma::vec xrand = arma::randu<arma::vec>(n);
    arma::vec yrand = arma::randu<arma::vec>(n);

    for (unsigned int i = 0; i < xrand.n_elem; i++) {
        this->xvec[i] = xrand(i);
        this->yvec[i] = yrand(i);
    }

    xrand.reset();
    yrand.reset();
}

double Openmp_class::add_element(size_t n)
{
    if ( n < this->size ) {
        return  this->xvec[n] + this->yvec[n];
    } else {
        string errmsg = "Openmp_class::add_element index n out of bounds!";
        throw runtime_error( errmsg );
    }
}

double Openmp_class::substract_element(size_t n)
{
    if ( n < this->size ) {
        return  this->xvec[n] - this->yvec[n];
    } else {
        string errmsg = "Openmp_class::substract_element index n out of bounds!";
        throw runtime_error( errmsg );
    }
}

arma::vec Openmp_class::add_elements(size_t upto_n)
{
    if ( upto_n < this->size ) {
        arma::vec results = arma::zeros<arma::vec>( upto_n );

        for (unsigned int i = 0; i < upto_n; i++ ) {
            results(i) = this->xvec[i] + this->yvec[i];
        }

        return results;
    } else {
        string errmsg = "Openmp_class::add_elements index n out of bounds!";
        throw runtime_error( errmsg );
    }
}

arma::vec Openmp_class::multiply_elements(size_t upto_n)
{
    if ( upto_n < this->size ) {
        arma::vec results = arma::zeros<arma::vec>( upto_n );

        for (unsigned int i = 0; i < upto_n; i++ ) {
            results(i) = this->xvec[i] * this->yvec[i];
        }

        return  results;
    } else {
        string errmsg = "Openmp_class::add_elements index n out of bounds!";
        throw runtime_error( errmsg );
    }
}

double *Openmp_class::multiply_elements()
{
    double *xy = new double[this->size ];

    for (unsigned int i = 0; i < this->size; i++) {
        xy[i] = this->xvec[i] * this->yvec[i];
    }

    return xy;
}

主文件main.cpp

#include <iostream>
#include <iomanip>
#include <cmath>

#define ARMA_USE_HDF5
#include <armadillo>
#include "openmp_class.h"
using namespace std;

//#define ARMA_OPEN_MP
int main(/*int argc, char *argv[]*/ void)
{
    Openmp_class Myclass;
    Myclass.generate_data( 10 );

    #ifdef ARMA_OPEN_MP
    {
        #pragma omp parallel
        {

        #pragma omp for
        for (unsigned int j = 10; j <= 500000; j++) {
            arma::vec (Openmp_class::*ptrmem) (size_t) = &Openmp_class::multiply_elements;

            Openmp_class TestClass;

            TestClass.generate_data( 5000 );
            arma::vec x_vec = (TestClass.*ptrmem)(4999);
            ptrmem = nullptr;
        }
        #pragma omp barrier
        }
    }
    #else
    {
        #pragma omp parallel
        {

        #pragma omp for
        for (unsigned int j = 10; j <= 500000; j++) {
            double* (Openmp_class::*ptre2mltply)() = &Openmp_class::multiply_elements;
            Openmp_class TestClass;

            TestClass.generate_data( 5000 );
            double* x_vec = (TestClass.*ptre2mltply)();

            x_vec = nullptr;
            delete [] x_vec;
            ptre2mltply = nullptr;
        }
        #pragma omp barrier
        }
    }
    #endif

    return 1;
}

有人已经解决这个问题了吗?有什么建议吗?

感谢您的宝贵时间。

附注指向函数(或类成员)的指针到底是如何在多个线程之间共享的?

最佳答案

在删除指针之前,不应将 nullptr 分配给它们。

在您的 dtor 中,您将 nullptr 分配给您的成员,然后释放它们。

this->xvec = nullptr;
this->yvec = nullptr;

delete [] this->xvec;
delete [] this->yvec;

也在主函数中:

x_vec = nullptr;
delete [] x_vec;
ptre2mltply = nullptr;

只需从代码中删除这些分配即可。

关于C++:OpenMP 并行循环内存泄漏,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57336950/

相关文章:

objective-c - 他们为什么要这样初始化指针?

memory-leaks - 从 Protractor 测试访问 chromes window.performance

c++ - 用于嵌套 for 循环的 OpenMP?

C++ - 将 decltype 与包含在模板类中的枚举一起使用

c++ - 重载 operator<< 用于 ostream 语法

linux - 有没有办法确定 Linux 中可用视频 RAM 的数量?

c - 使用 OpenMP 和 OpenSSL 时的内存泄漏和段错误

C++ 继承获取错误

c++ - 需要读取文本文件 C++ 中某些字符之间的文本

c++ - 用于最小值、最大值、中值、平均值的 OpenMp C++ 算法