使用 C 乘以随机生成的巨大矩阵时出错

Error in multiplying randomly generated matrices of huge sizes using C

我的主要目标是通过在 C 语言和 Java 各种环境中对矩阵乘法算法进行基准测试来证明虚拟化与容器化有何不同,并得出合适的结论。

我选择这个算法的原因是因为矩阵乘法是各种计算机科学领域中非常常用的算法,因为它们大多处理大尺寸,我希望优化我的代码以便能够执行操作到至少 2000x2000 矩阵大小,这样两者之间的区别就很明显了。

我在 Linux 上使用 GCC,在 Windows 上使用 Code::Blocks 中的默认 C 编译器(我不知道使用哪个版本的 GCC)。

问题是,当我 运行 Windows 上的代码时,编译器只接受最大 490x490 的大小,如果超过该大小,则会转储核心。 Linux 设法克服了这个问题,但不能超过 590x590。

我最初以为我的设备内存是原因,并请了几个机器更好的朋友运行相同的代码,但结果还是一样。

仅供参考:我运行正在使用 Pentium N3540 和 4GB DDR3 RAM。我的朋友 运行宁 i7-8750H 与 16GB DDR4 和另一个 i5-9300H 与 8GB DDR4。

这是我写的代码:

#include <stdio.h>
#include <stdlib.h>
#define MAX 10

int main()
{
    long i, j, k, m, n;
    printf("Enter the row dimension of the matrix: "); scanf("%ld", &m);
    printf("Enter the column dimension of the matrix: "); scanf("%ld", &n);
    long mat1[m][n], mat2[m][n], mat3[m][n];

    for(i=0; i<m; i++)
        for(j=0; j<n; j++)
        {
            mat1[i][j] = (long)rand()%MAX;
            mat2[i][j] = (long)rand()%MAX;
            mat3[i][j] = 0;
        }

    printf("\n\nThe matrix 1 is: \n");
    for(i=0; i<m; i++)
    {
        for(j=0; j<n; j++)
        {
            printf("%d\t", (int)mat1[i][j]);
        }
        printf("\n");
    }

    printf("\n\nThe matrix 2 is: \n");
    for(i=0; i<m; i++)
    {
        for(j=0; j<n; j++)
        {
            printf("%d\t", (int)mat2[i][j]);
        }
        printf("\n");
    }

    for (i = 0; i < m; i++)
        for (j = 0; j < n; j++)
            for (k = 0; k < n; k++)
                mat3[i][j] += mat1[i][k] * mat2[k][j];

    printf("\n\nThe resultant matrix is: \n");
    for(i=0; i<m; i++)
    {
        for(j=0; j<n; j++)
        {
            printf("%d\t", (int)mat3[i][j]);
        }
        printf("\n");
    }
    return 0;
}

除了 @EdHeal 建议使用 malloc() 之外,您还可以简单地使用 static 使您的变量成为全局变量,强制将其放置在 [=24= 之外]stack in the heap - 假设你不介意不可变矩阵。

因为无论如何你必须制作可变长度的数组malloc()自然适合你的use-case。

栈是用来放小东西的;大东西的堆——用你自己的话来说,这些是“巨大尺寸”的矩阵:)

作为对那些在 C 编程方面更有经验的人的旁注 - 为什么没有更多的 C 教科书教授 stack-heap 非 malloc()ed [=] 的理论和大小限制14=] 变量 ? 为什么每个新手都必须通过跌倒并在 S.O 上被告知来学习?

当你这样做时

long mat1[m][n], mat2[m][n], mat3[m][n];

您创建了一个具有自动存储持续时间的对象(又名变量)。即对象在函数执行时自动创建,函数退出时自动销毁。

C 标准没有描述如何做到这一点。这留给了实施标准的系统。最常见的方法是使用所谓的堆栈。这是一个内存区域,为您的程序 pre-allocated。每当您的程序调用函数时,函数内定义的任何变量都可以放在该堆栈上。这样可以非常简单快速地为此类变量分配内存。

但是,它有一个缺点 - 堆栈的大小有限(而且相当小)。因此,如果一个函数使用巨大的变量,您可能 运行 超出堆栈内存。不幸的是,大多数系统直到为时已晚才检测到这一点。

避免这种情况的简单规则是:不要定义具有自动存储持续时间的大变量(也称为大函数局部变量)。

因此对于您的具体示例,您应该替换:

long mat1[m][n]

long (*mat1)[n] = malloc(m * sizeof *mat1); // This defines mat1 as a pointer
if (mat1 == NULL)                           // to an array of n longs and
{                                           // allocate memory of m such arrays.
    // Out of memory                        // In other words:
    exit(1);                                // A m by n matrix of long
}

// From here on you can use mat1 as a 2D matrix
// example:
mat1[4][9] = 42;

...

// Once you are done using mat1, you need to free the memory. Like:
free(mat1);