std::fill数组较大时出现segmentation fault错误

std::fill segmentation fault error when the array is large

我有下面的class,它类似于二维的标量场,但由于可能使用周期性边界条件,因此也有幻影区(只需将其视为二维矩阵)。

#include <algorithm>
#include <iostream>
#include <fftw3.h>

class RectMesh
{
private:

  int cols_x;
  int rows_y;
  int nghost;
  double* mesh;

public:

  void CheckConstr(int& cols, int& rows, int& ghost);
  RectMesh(int cols=2, int rows=2, int ghost=1);

  /* Rule of 5 */
  ~RectMesh();
  RectMesh(const RectMesh& obj);
  RectMesh(RectMesh&& tmp) noexcept;
  RectMesh& operator=(RectMesh rhs);
  RectMesh& operator=(RectMesh&& tmp);
  
};

构造函数实现是

/*--------------------- Constructor -----------------------------*/
void RectMesh::CheckConstr(int& cols, int& rows, int& ghost)
{
  if (cols < 2 || rows < 2 || ghost < 0)
    {
      std::cout << "The smallest mesh must have dimensions (2x2)"
    "and the minimum number of ghost points is zero. Exiting."
        << std::endl; 
      exit(EXIT_FAILURE);
    }
}

RectMesh::RectMesh(int cols, int rows, int ghost)
  : cols_x(cols), rows_y(rows), nghost(ghost), mesh(nullptr)
{
  CheckConstr(cols,rows,ghost);
  int len = (cols_x+2*nghost)*(rows_y + 2*nghost);
  mesh = (double*) fftw_malloc(len*sizeof(double));
  std::fill(mesh, mesh+len, 0.0);
  std::cout << "RectMesh constructor called." << std::endl;
}

主要功能

int main()
{
  int cols = 1e6;
  int rows = 1e6;
  int nghost = 2;
  RectMesh A(cols,rows,nghost);
  return 0;
}

控制台输出: Segmentation fault (core dumped)

当我注释掉 std::fill 或当我有 rows = cols = 1e5.

时,这不会发生

这是为什么?

假设您是 运行 一台普通或典型的计算机,1e6 列乘 1e6 行的 doubles 是

1000000 * 1000000 * 8 bytes = 8 TB (or 7.28 TiB)

所以答案是:检查 fftw_malloc 的 return 值,而您没有检查。有可能 它失败了并且 return 编辑了一个空指针 ,这肯定会在您尝试访问它时造成混乱。

另外,检查乘法的结果。 int 很可能是 4 字节并且不包含这样的值(一些 43 位整数)。改用 size_t


如果将每个维度减小到 1e5,结果将是 80 GB (74.51 GiB),这可能适合大型服务器。

int len = (cols_x+2*nghost)*(rows_y + 2*nghost);

cols_xrows_y代入1e6,nghost代入2,然后乘以sizeof(double)即8,总计为:

8000064000128

字节,或您尝试分配的超过 7 TB 的内存。这里发生了两件事之一:

  1. fftw_malloc 对此大笑,returns NULL,您显示的代码无法检查其 return 值,并发现没有分配任何东西,或者

  2. 实际乘法溢出(如果在 32 位平台上),结果同样荒谬。