通过引用传递大对象时堆栈溢出

时间:2014-03-08 17:23:59

标签: c++ matrix stack-overflow

我有一个c ++类,它包含表示预设长度向量的结构和预设大小的矩阵。每个向量只是一个双精度数组,每个矩阵是一个向量数组。我选择不使用C ++提供的Vector类,因为我根本不需要调整向量的大小,也不会使用向量的任何实例方法。我只是想在我的双阵列周围寻找一个包装器。

该类的目标是通过将矩阵分解为更小的块然后使用MPI在我们的本地计算集群上的多个节点上执行乘法来执行2个大矩阵(512x512)的矩阵乘法。当我试图将矩阵分解为较小的块时,我遇到了堆栈溢出异常的问题。这是一些代码:

// Vector Structs
struct Vec512 { double values[512]; };
struct Vec256 { double values[256]; };
struct Vec128 { double values[128]; };
struct Vec64 { double values[64]; };

// Matrix Structs
struct Mat512 { 
    Vec512 rows[512]; 
    Mat512(){}
    Mat512(MatrixInitEnum e){
        switch(e){
            case Empty:
                for(int row = 0; row < 512; row++){
                Vec512 temp;
                for(int col = 0; col < 512; col++){
                    temp.values[col] = 0;
                }
                rows[row] = temp;
            }
            break;
            case Random:
                for(int row = 0; row < 512; row++){
                    Vec512 temp;
                    for(int col = 0; col < 512; col++){
                        temp.values[col] = myRandom();
                    }
                    rows[row] = temp;
                }
                break;
            }
    }
    Vec512 GetRow(int row){
        return rows[row];
    }
    Vec512 GetColumn(int col){
        Vec512 column;
        for(int i = 0; i < 512; i++){
            column.values[i] = rows[i].values[col];
        }
        return column;
    }
    void SetValue(int row, int col, double value){
        rows[row].values[col] = value;
    }
    double GetValue(int row, int col){
        return rows[row].values[col];
    }
};
// Analogous structs for Mat256, Mat128, Mat64

/*Decomposes the big matrix into 4 256x256 matrices in row-major fashion*/
Mat256* DecomposeMatrix256(Mat512 *bigMat){
    Mat256 matArray[4];
    int beginRow, endRow, beginCol, endCol, rowOffset, colOffset;

    for(int it = 0; it < 4; it++){
        beginRow = (it/2) * 256;
        endRow = beginRow + 256;
        beginCol = (it % 2) * 256; 
        endCol = beginCol + 256;
        rowOffset = (it / 2) * 256;
        colOffset = (it % 2) * 256;

        for(int row = beginRow; row < endRow; row++){
            for(int col = beginCol; col < endCol; col++){
                double val = bigMat->GetValue(row, col);
                matArray[it].SetValue(row - rowOffset, col - colOffset, val);
            }
        }
    }

    return matArray;
}

// Analogous methods for breaking into 16 128x128 Mat128s and 64 64x64 Mat64s

然后我的主要方法就是

int main(int argc, char* argv[])
{
    cout << "Welcome, the program is now initializing the matrices.\n";

    Mat512* bigMat = new Mat512(Random);     // Creates this just fine
    Mat256* mats256 = DecomposeMatrix256(bigMat);    // Gets here and can step to the signature of the method above without issue

    // MPI code to split up the multiplication and to 
    // wait until user is ready to exit

    return 0;
}

以下是我的问题: 我可以创建大Mat512我的随机值没问题。我在创建大矩阵的位置设置了一个断点,并验证它是否已成功创建。然后我进入了对DecomposeMatrix256(Mat512 * bigMat)的调用,看到我正在使用该方法没问题。此外,当悬停在bigMat对象上时,visual studio向我展示它确实收到了大矩阵。当我尝试进入该方法时,我立即得到了堆栈溢出异常。

我感到困惑的是为什么在我创建另一个新对象(比如4个256x256矩阵的数组)之前我会得到堆栈溢出。我很确定我通过引用而不是通过值传递矩阵(我已经习惯了C#而不是C ++,所以我很高兴听到我只是在引用传递时做错了所以我认为不会简单地将引用传递给大矩阵是一个很大的开销。

我能够通过进入项目配置设置并将堆栈保留大小从1MB(默认值)增加到8MB来解决我的问题(可能是过度杀伤但我只是希望它能够用于我的调试目的)。

当我简单地传递对大矩阵的引用而不是矩阵本身(按值)时,有人可以解释为什么我会得到溢出吗?再次,我通过增加堆栈大小来实现它,但我不明白为什么当我通过引用而不是通过值传递对象时这是必要的。

感谢阅读和输入。我很乐意发布任何与帮助理解我的问题相关的其他内容。

2 个答案:

答案 0 :(得分:3)

DecomposeMatrix256()在堆栈上创建一个包含四个Mat256对象的数组。这很可能导致溢出,因为它需要大量的堆栈空间。您传递的参数不是溢出的原因。

另一个问题是,该函数返回一个指向局部变量的指针,该局部变量将在函数末尾超出范围。此指针将不再指向有效对象。

答案 1 :(得分:1)

这是因为在方法DecomposeMatrix256中,您在堆栈上创建自动变量:

Mat256* DecomposeMatrix256(Mat512 *bigMat){
    Mat256 matArray[4];

此大小为4*256*256*sizeof(double),在x64位计算机上为4*256*256*8 2 097 152 字节太多而无法放入堆栈,因此溢出。