一次C++内存错误的解决思路

Hello, 欢迎登录 or 注册!

/ 0评 / 0

本文作者:  本文分类:编程学习笔记  浏览:250
阅读时间:1967字, 约2-3.5分钟

前情提要:昨天srt同学给我看了一段代码,出现了一个很奇怪的问题,就是cout出现在程序main函数的最前面,却没有输出:

#include<bits/stdc++.h>
using namespace std;
const int MOD=2009;
const int N=105;
struct Matrix
{
    int a[N][N];
    int n,m;
    Matrix(int n=0,int m=0):n(n),m(m){memset(a,0,sizeof(a));}
    void init(int _n=0,int _m=0){n=_n;m=_m;memset(a,0,sizeof(a));}
    
    Matrix operator*(Matrix b)
    {
        /*
        省略
        */

        return ans;
    }
    
};

Matrix qpow(Matrix a,int n)
{
    /*
    省略
    */

}
int n,t,cnt;
int main()
{
    cout << "hello world\n" << endl;
    cin>>n>>t; 
    Matrix A,B;
    /*
    省略
    */

    return 0;
}

经过研究与和hyq同学的讨论,我最终找到了这个问题的根源。

打开gdb,在CPU Dump中,指出了问题所在的位置:

是“__chkstk_ms()”中的问题。不过似乎这不能说明什么问题,我们就继续查找思路。

首先,我们打开任务管理器,发现过程是RAM占用不断增加,直至报Segmentation Fault,被迫中止。因此确定了问题在于内存爆了导致的段错误。

我昨晚和hyq讨论了很久是否是在循环过程中因为大量创建的临时变量未被析构而导致占用了大量内存,但是事实证明并非如此。其实就是开了1005*1005的int数组就大到足以报错了。如这段我简化过后的程序:

#include <bits/stdc++.h>
using namespace std;

int main() {
    system("pause");
    int x[1000][1000];
    memset(x,0,sizeof(x));
    return 0;
}

在电脑上会重现与昨日一样的错误。因此这个“哪里出了问题”这个问题已经被解决了。

下一个问题,为什么昨天即使把 Matrix A,B; 这个定义语句放到了cout的后面,cout也无法输出。

我通过Compiler Explorer(https://godbolt.org/,超级好用)查看了编译我写的测试程序得到的汇编代码,摘录如下:

main:
       sub     rsp, 4000008
       mov     edx, 4000000
       mov     esi, 0
       mov     rdi, rsp
       call    memset
       mov     eax, 0
       add     rsp, 4000008
       ret

可以看到,程序的入口点处(即“main”的后一行)就出现了对rsp寄存器值减去4000008的操作,而4000000就是1000*1000*4(sizeof int),所以这些变量会占用的栈空间在程序开头即被预留,注意rsp即为栈顶指针,减去后它小于了栈基指针的值,便出现了段错误。问题至此就解释清楚了。

注意在我为了复现而编写的代码中保留了 memset(x,0,sizeof(x)) 一句,因为只有通过memset初始化了后C++才会预留这一部分空间。对于下列代码

int main() {
    int x[1000][1000];
    return 0;
}

编译得到的汇编是

main:
        mov     eax, 0
        ret

并没有预留空间的操作。

关于作者

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注