查内存覆盖的经验,大家能不能总结一下?
我的实践:
1,查找泄露:首先查找内存泄露,内存泄露往往能提供内存覆盖的线索,比如:应该释放A,结果错误的释放B,导致A泄露、B破坏。 2,使用工具:用Numega检查看能不能报错。 3,搜索法:查找delete,memcpy,free三个函数和线程相关函数,检查是否有问题; 4,猜测遍历法:根据对出问题代码的怀疑程度,依次删除这些代码,直到不再出现覆盖位置,找到对应的问题代码。 不知道这算不算方法 |
回复: 查内存覆盖的经验,大家能不能总结一下?
1 定位被覆盖的内存地址
2 开始调试,在memory窗口中观察该地址内存的变化 3 若观察到在两个断点之间内存被覆盖了,则可以逐步缩小断点范围,找到发生覆盖的代码 4 可重点留意数组操作和字符串 5 如果是在一个循环中发生覆盖(例如在循环中写数组溢出),需要利用条件断点功能(当 i = xx 次的时候断住),省得你按很多次F5 |
回复: 查内存覆盖的经验,大家能不能总结一下?
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宏, 详见附录。 #if USE_SS_LOG_TRACE #define SSLOG g_log.Log #else #define SSLOG 1 ? (void)0 : g_log.Log #endif 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 ¸¡µã¼ÆËã·½³Ì×éµü´ú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\\¼¯³É\\ËïÑ©Çà\\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±äÁ ¿Êý\t·½³ÌÊý\tµü´ú´ÎÊý\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解决了再说 |
回复: 查内存覆盖的经验,大家能不能总结一下?
经验总结:
设条件断点在heap allocation的位置即可。 |
回复: 查内存覆盖的经验,大家能不能总结一下?
|
所有的时间均为北京时间。 现在的时间是 08:07 PM. |