• 查内存覆盖从以前的帖子里总结的


    我的实践:
    1,查找泄露:首先查找内存泄露,内存泄露往往能提供内存覆盖的线索,比如:应该释放A,结果错误的释放B,导致A泄露、B破坏。
    2,使用工具:用Numega检查看能不能报错。
    3,搜索法:查找delete,memcpy,free三个函数和线程相关函数,检查是否有问题;
    4,猜测遍历法:根据对出问题代码的怀疑程度,依次删除这些代码,直到不再出现覆盖位置,找到对应的问题代码。
    不知道这算不算方法
    1 定位被覆盖的内存地址
    2 开始调试,在memory窗口中观察该地址内存的变化
    3 若观察到在两个断点之间内存被覆盖了,则可以逐步缩小断点范围,找到发生覆盖的代码
    4 可重点留意数组操作和字符串
    5 如果是在一个循环中发生覆盖(例如在循环中写数组溢出),需要利用条件断点功能(当 i = xx 次的时候断住),省得你按很多次F5
    以前遇到覆盖好像是这么查的。。。快2年没写大段代码了,忘得差不多了。

    1,(内存泄漏)根据 vc ide debugger 的 memory leak dump 判断以及检查内存泄漏。有的时候由于
    内存覆盖而无法得知文件名,这是可以查找所有的new, 根据 new 所在的代码行 比对 dump 确定泄漏
    的位置。
    2,(内存覆盖和内存泄漏)使用 numega boundschecker。
    3,(内存泄漏)使用对象计数器。如果怀疑存在对象内存泄漏的话。在构造函数中计数器 ++, 在析
    构函数中 对象计数器 -- 。
    4,(内存覆盖和内存泄漏)进行大量反复的操作,用 task list 观察是否内存一直在增加。
    5,防止内存泄漏的方法。
    a)分配缓冲区的时候避免使用 new,而要使用 CArray 或者 vector 等动态数组。
    b)一旦使用一个 new ,一定要立即考虑它的 delete。
    // 原来是说内存覆盖阿。
    6,内存覆盖严重的时候,往往导致系统异常,无法调试。这个时候需要采用 log file, console log
    , beep 等方法。用大量的 print 输出,确定执行流,进而定位崩溃位置。采用下面代码定义log宏,
    详见附录。
    7,内存覆盖的时候,往往会有崩溃位置不确定的问题。这是需要观察 vc ide debugger 输出的

    exception 信息,那往往是发生内存覆盖的第一手消息。

    8,可以采用 try catch(...) 的方法防止崩溃的一塌糊涂,并且可以一步步缩小包围圈,精确定位代

    码。

    9,对于怀疑的数据,在程序执行流中频繁调用合法性检查的函数。对于整数,根据程序的意义确定一

    个合理范围,比如 0 ~ 100000。对于浮点数可以采用 _isnan(), _finite() 等函数检查合法性,在浮

    点数合法的情况下,要进一步检查取值范围的合法性。字符串数据则需要检查它的长度,并且输出其内

    容,供观察。 一旦检查代码 发现数据的问题,就立即用ASSERT报告。这样可以一步步顺着执行流往前

    推,直到定位到有问题的代码。除了对被怀疑数据进行自动代码的检查之外,还可以输出。见上面一条

    (log)。

    10,对于怀疑的内存越界,特别是数组越界,可以在那个数组后面定义一个缓冲数组。在被怀疑有破坏

    作用的代码之前,初始化缓冲数组,在破坏代码之后,检查缓冲数组,一旦有问题,就立即报告。一步

    步顺着执行流往前推,直到定位到有问题的代码。





    附录:

    1,log 类,可以方便的进行log
    #define USE_SS_LOG_TRACE 1

    class SSLog
    {
    public:
    void Log(LPCTSTR lpszFormat, ...);
    int32 Open();
    SSLog();
    virtual ~SSLog();

    static void CALLBACK FlushBuf(HWND hwnd, UINT uMsg, UINT idEvent, DWORD dwTime);

    static FILE *m_pFile;
    };

    #if !USE_SS_LOG
    #undef USE_SS_LOG_TRACE
    #define USE_SS_LOG_TRACE 0
    #endif

    #if USE_SS_LOG_TRACE
    #define SSLOG g_log.Log
    #else
    #define SSLOG 1 ? (void)0 : g_log.Log
    #endif



    FILE *SSLog::m_pFile;

    SSLog::SSLog()
    {
    m_pFile = NULL;
    }

    SSLog::~SSLog()
    {
    if(m_pFile)
    {
    Log("#1 ss dll terminated.\n");
    fclose(m_pFile);
    }
    }

    /**
    #1 ??í¨log
    #2 ??μ?????·?3ì×éμü′úlog
    #3 graph solver
    #4 SSketchSolver::Solve entry
    #5 ????′í?ó
    #6 explode numerical vars
    #7 time out control
    #8 cluster scale log
    #9 whole time consumed in one solving
    #10 ???é±è???ó?ú′?·???
    #11 ASSERT(jude<2);
    */

    int32 SSLog::Open()
    {
    #if USE_SS_LOG
    if(!m_pFile)
    {
    /*
    Controls stream buffering and buffer size.
    int setvbuf( FILE *stream, char *buffer, int mode, size_t size );
    */


    CString strFile = "\\\\Urtsoftserver\\development\\?ˉ3é\\?????à\\sslog\\";
    TCHAR pszName[MAX_PATH];
    DWORD dwSize=MAX_PATH;
    GetComputerName(pszName, &dwSize);
    pszName[dwSize] = 0;
    strFile = strFile + pszName + ".txt";
    if(!m_pFile)
    m_pFile = fopen(strFile, "a");

    if(m_pFile)
    {
    setvbuf(m_pFile, NULL, _IOFBF, 2048);
    }

    CTime time = CTime::GetCurrentTime();
    CString strTime = time.Format("%Y-%m-%d %H:%M:%S");
    Log("#1 ss dll started (%s) s3k Build %d (%s) ----------------------\n±?á

    ?êy\t·?3ìêy\tμü′ú′?êy\tμü′úê±??\n",
    (LPCTSTR)strTime,
    YA_BUILD_NO,
    __TIMESTAMP__);

    SetTimer(NULL, 12, 2000, FlushBuf);
    }
    #endif
    return TRUE;
    }

    void SSLog::Log(LPCTSTR lpszFormat, ...)
    {
    // static int32 cc;
    // CONOUT("log cc %d\n", cc++);
    if(m_pFile)
    {
    va_list args;
    va_start(args, lpszFormat);

    int nBuf;
    TCHAR szBuffer[512];

    nBuf = _vsntprintf(szBuffer, 512, lpszFormat, args);
    if(nBuf<0)
    {
    fputs(lpszFormat, m_pFile);
    }
    else
    {
    // was there an error? was the expanded string too long?
    ASSERT(nBuf >= 0);
    fputs(szBuffer, m_pFile);
    }

    va_end(args);
    }
    else
    {
    CONOUT("error, no log file did not open.");
    }

    // CONOUT("log end.\n");
    }

    void CALLBACK SSLog::FlushBuf(HWND hwnd, UINT uMsg, UINT idEvent, DWORD dwTime)
    {
    if(m_pFile)
    {
    fflush(m_pFile);
    }
    }


    1.查系统回调函数的调用规则是否正确,__cdecl和__stdcall的清栈角色不同有可能造成访问违规
    2.用折半法确认出错位置,出错位置前对该内存的操作都可疑,在分配该内存处打断点,记下分配的内存地址,新建断点,新断点条件是该内存发生变化即断下
    3.检查多线程访问变量的互斥和同步
    4.若使用了别的dll的导出数据(导出全局变量是没有模块引用计数的),dll是否被提前释放?
    5.是否多次delete同一变量,带[]的和不带的配套
    6.crt是否是正确的线程版本



    养好写代码习惯,分配内存后马上写释放内存的代码,以保证代码永远是健康的可测的.若分配和释放之间有多个返回点(return,exception),可新建ResourceHelper,利用ctor和dtor进行资源管理
    发现有错误时,马上停止手头工作,把bug解决了再说
  • 相关阅读:
    w10更新
    java.lang.Integer cannot be cast to java.math.BigDecimal
    加法add 乘法multiply
    iterator,hasNext,next
    购物车全部数据,带商品信息
    ERRORinit datasource error, url: jdbc:mysql://localhost:3306/xxxxxx?useUnicode=true&characterEncoding=gbk&serverTimezone=GMT&useSSL=false
    Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.7.0:
    创建一个场景
    window系统已发布,等待更新
    [转]向量(矩阵)范式理解(0范式,1范式,2范式,无穷范式)
  • 原文地址:https://www.cnblogs.com/caoshenghe/p/1574019.html
Copyright © 2020-2023  润新知