|

楼主 |
发表于 2007-8-5 21:26:47
|
显示全部楼层
回复: 查内存覆盖的经验,大家能不能总结一下?
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: og(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);
}
} |
|