查看单个帖子
旧 2007-08-05, 09:26 PM   #3
yogy
高级会员
 
注册日期: 06-11
帖子: 1527
精华: 15
现金: 6353 标准币
资产: 6353 标准币
yogy 向着好的方向发展
默认 回复: 查内存覆盖的经验,大家能不能总结一下?

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\\&frac14;&macr;&sup3;&Eacute;\\&Euml;&iuml;&Ntilde;&copy;&Ccedil;à\\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±&auml;&Aacute;

&iquest;&Ecirc;&yacute;\t·&frac12;&sup3;&Igrave;&Ecirc;&yacute;\t&micro;ü&acute;ú&acute;&Icirc;&Ecirc;&yacute;\t&micro;ü&acute;ú&Ecirc;±&frac14;&auml;\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);
}
}
yogy离线中   回复时引用此帖