Memory Manager使用(内存泄漏解决方案)

Memory Manager 是一款功能完备的内存泄露检测模块,能找到具体的内存泄漏的位置,不过目前关于该类的使用方法较少,特做个简要的说明。

MMGR 主要文件如下:

//

// MMGR.CPP

//

 

// ---------------------------------------------------------------------------------------------------------------------------------
//
//
// _ __ ___ _ __ ___ __ _ _ __ ___ _ __ _ __
// | '_ ` _ /| '_ ` _ / / _` | '__| / __| '_ /| '_ /
// | | | | | | | | | | | (_| | | _ | (__| |_) | |_) |
// |_| |_| |_|_| |_| |_|/__, |_| (_) /___| .__/| .__/
// __/ | | | | |
// |___/ |_| |_|
//
// Memory manager & tracking software
//
// Best viewed with 8-character tabs and (at least) 132 columns
//
// ---------------------------------------------------------------------------------------------------------------------------------
//
// Restrictions & freedoms pertaining to usage and redistribution of this software:
//
// * This software is 100% free
// * If you use this software (in part or in whole) you must credit the author.
// * This software may not be re-distributed (in part or in whole) in a modified
// form without clear documentation on how to obtain a copy of the original work.
// * You may not use this software to directly or indirectly cause harm to others.
// * This software is provided as-is and without warrantee. Use at your own risk.
//
// For more information, visit HTTP://www.FluidStudios.com
//
// ---------------------------------------------------------------------------------------------------------------------------------
// Originally created on 12/22/2000 by Paul Nettle
//
// Copyright 2000, Fluid Studios, Inc., all rights reserved.
// ---------------------------------------------------------------------------------------------------------------------------------
//
// !!IMPORTANT!!
//
// This software is self-documented with periodic comments. Before you start using this software, perform a search for the string
// "-DOC-" to locate pertinent information about how to use this software.
//
// You are also encouraged to read the comment blocks throughout this source file. They will help you understand how this memory
// tracking software works, so you can better utilize it within your applications.
//
// NOTES:
//
// 1. If you get compiler errors having to do with set_new_handler, then go through this source and search/replace
// "std::set_new_handler" with "set_new_handler".
//
// 2. This code purposely uses no external routines that allocate RAM (other than the raw allocation routines, such as malloc). We
// do this because we want this to be as self-contained as possible. As an example, we don't use assert, because when running
// under WIN32, the assert brings up a dialog box, which allocates RAM. Doing this in the middle of an allocation would be bad.
//
// 3. When trying to override new/delete under MFC (which has its own version of global new/delete) the linker will complain. In
// order to fix this error, use the compiler option: /FORCE, which will force it to build an executable even with linker errors.
// Be sure to check those errors each time you compile, otherwise, you may miss a valid linker error.
//
// 4. If you see something that looks odd to you or seems like a strange way of going about doing something, then consider that this
// code was carefully thought out. If something looks odd, then just assume I've got a good reason for doing it that way (an
// example is the use of the class MemStaticTimeTracker.)
//
// 5. With MFC applications, you will need to comment out any occurance of "#define new DEBUG_NEW" from all source files.
//
// 6. Include file dependencies are _very_important_ for getting the MMGR to integrate nicely into your application. Be careful if
// you're including standard includes from within your own project inclues; that will break this very specific dependency order.
// It should look like this:
//
// #include <stdio.h> // Standard includes MUST come first
// #include <stdlib.h> //
// #include <streamio> //
//
// #include "mmgr.h" // mmgr.h MUST come next
//
// #include "myfile1.h" // Project includes MUST come last
// #include "myfile2.h" //
// #include "myfile3.h" //
//
// ---------------------------------------------------------------------------------------------------------------------------------

#include "stdafx.h"

#ifdef MMGR

#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <string.h>
#include <time.h>
#include <stdarg.h>
#include <new>

using namespace std;

#ifndef WIN32
#include <unistd.h>
#endif

#include "mmgr.h"

// ---------------------------------------------------------------------------------------------------------------------------------
// -DOC- If you're like me, it's hard to gain trust in foreign code. This memory manager will try to INDUCE your code to crash (for
// very good reasons... like making bugs obvious as early as possible.) Some people may be inclined to remove this memory tracking
// software if it causes crashes that didn't exist previously. In reality, these new crashes are the BEST reason for using this
// software!
//
// Whether this software causes your application to crash, or if it reports errors, you need to be able to TRUST this software. To
// this end, you are given some very simple debugging tools.
//
// The quickest way to locate problems is to enable the STRESS_TEST macro (below.) This should catch 95% of the crashes before they
// occur by validating every allocation each time this memory manager performs an allocation function. If that doesn't work, keep
// reading...
//
// If you enable the TEST_MEMORY_MANAGER #define (below), this memory manager will log an entry in the memory.log file each time it
// enters and exits one of its primary allocation handling routines. Each call that succeeds should place an "ENTER" and an "EXIT"
// into the log. If the program crashes within the memory manager, it will log an "ENTER", but not an "EXIT". The log will also
// report the name of the routine.
//
// Just because this memory manager crashes does not mean that there is a bug here! First, an application could inadvertantly damage
// the heap, causing malloc(), realloc() or free() to crash. Also, an application could inadvertantly damage some of the memory used
// by this memory tracking software, causing it to crash in much the same way that a damaged heap would affect the standard
// allocation routines.
//
// In the event of a crash within this code, the first thing you'll want to do is to locate the actual line of code that is
// crashing. You can do this by adding log() entries throughout the routine that crashes, repeating this process until you narrow
// in on the offending line of code. If the crash happens in a standard C allocation routine (i.e. malloc, realloc or free) don't
// bother contacting me, your application has damaged the heap. You can help find the culprit in your code by enabling the
// STRESS_TEST macro (below.)
//
// If you truely suspect a bug in this memory manager (and you had better be sure about it! :) you can contact me at
// [email protected]. Before you do, however, check for a newer version at:
//
// http://www.FluidStudios.com/publications.html
//
// When using this debugging aid, make sure that you are NOT setting the alwaysLogAll variable on, otherwise the log could be
// cluttered and hard to read.
// ---------------------------------------------------------------------------------------------------------------------------------

//#define TEST_MEMORY_MANAGER

// ---------------------------------------------------------------------------------------------------------------------------------
// -DOC- Enable this sucker if you really want to stress-test your app's memory usage, or to help find hard-to-find bugs
// ---------------------------------------------------------------------------------------------------------------------------------

//#define STRESS_TEST

// ---------------------------------------------------------------------------------------------------------------------------------
// -DOC- Enable this sucker if you want to stress-test your app's error-handling. Set RANDOM_FAIL to the percentage of failures you
// want to test with (0 = none, >100 = all failures).
// ---------------------------------------------------------------------------------------------------------------------------------

//#define RANDOM_FAILURE 10.0

// ---------------------------------------------------------------------------------------------------------------------------------
// -DOC- Locals -- modify these flags to suit your needs
// ---------------------------------------------------------------------------------------------------------------------------------

#ifdef STRESS_TEST
static const unsigned int hashBits = 12;
static bool randomWipe = true;
static bool alwaysValidateAll = true;
static bool alwaysLogAll = true;
static bool alwaysWipeAll = true;
static bool cleanupLogOnFirstRun = true;
static const unsigned int paddingSize = 1024; // An extra 8K per allocation!
#else
static const unsigned int hashBits = 12;
static bool randomWipe = false;
static bool alwaysValidateAll = false;
static bool alwaysLogAll = false;
static bool alwaysWipeAll = true;
static bool cleanupLogOnFirstRun = true;
static const unsigned int paddingSize = 4;
#endif

// ---------------------------------------------------------------------------------------------------------------------------------
// We define our own assert, because we don't want to bring up an assertion dialog, since that allocates RAM. Our new assert
// simply declares a forced breakpoint.
//
// The BEOS assert added by Arvid Norberg <[email protected]>.
// ---------------------------------------------------------------------------------------------------------------------------------

#ifdef WIN32
#ifdef _DEBUG
#define m_assert(x) if ((x) == false) __asm { int 3 }
#else
#define m_assert(x) {}
#endif
#elif defined(__BEOS__)
#ifdef DEBUG
extern void debugger(const char *message);
#define m_assert(x) if ((x) == false) debugger("mmgr: assert failed")
#else
#define m_assert(x) {}
#endif
#else // Linux uses assert, which we can use safely, since it doesn't bring up a dialog within the program.
#define m_assert(cond) assert(cond)
#endif

// ---------------------------------------------------------------------------------------------------------------------------------
// Here, we turn off our macros because any place in this source file where the word 'new' or the word 'delete' (etc.)
// appear will be expanded by the macro. So to avoid problems using them within this source file, we'll just #undef them.
// ---------------------------------------------------------------------------------------------------------------------------------

#undef new
#undef delete
#undef malloc
#undef calloc
#undef realloc
#undef free

// ---------------------------------------------------------------------------------------------------------------------------------
// Defaults for the constants & statics in the MemoryManager class
// ---------------------------------------------------------------------------------------------------------------------------------

const unsigned int m_alloc_unknown = 0;
const unsigned int m_alloc_new = 1;
const unsigned int m_alloc_new_array = 2;
const unsigned int m_alloc_malloc = 3;
const unsigned int m_alloc_calloc = 4;
const unsigned int m_alloc_realloc = 5;
const unsigned int m_alloc_delete = 6;
const unsigned int m_alloc_delete_array = 7;
const unsigned int m_alloc_free = 8;

// ---------------------------------------------------------------------------------------------------------------------------------
// -DOC- Get to know these values. They represent the values that will be used to fill unused and deallocated RAM.
// ---------------------------------------------------------------------------------------------------------------------------------

static unsigned int prefixPattern = 0xbaadf00d; // Fill pattern for bytes preceeding allocated blocks
static unsigned int postfixPattern = 0xdeadc0de; // Fill pattern for bytes following allocated blocks
static unsigned int unusedPattern = 0xfeedface; // Fill pattern for freshly allocated blocks
static unsigned int releasedPattern = 0xdeadbeef; // Fill pattern for deallocated blocks

// ---------------------------------------------------------------------------------------------------------------------------------
// Other locals
// ---------------------------------------------------------------------------------------------------------------------------------

static const unsigned int hashSize = 1 << hashBits;
static const char *allocationTypes[] = {"Unknown",
"new", "new[]", "malloc", "calloc",
"realloc", "delete", "delete[]", "free"};
static sAllocUnit *hashTable[hashSize];
static sAllocUnit *reservoir;
static unsigned int currentAllocationCount = 0;
static unsigned int breakOnAllocationCount = 0;
static sMStats stats;
static const char *sourceFile = "??";
static const char *sourceFunc = "??";
static unsigned int sourceLine = 0;
static bool staticDeinitTime = false;
static sAllocUnit **reservoirBuffer = NULL;
static unsigned int reservoirBufferSize = 0;
static const char *memoryLogFile = "memory.log";
static const char *memoryLeakLogFile = "memleaks.log";
static void doCleanupLogOnFirstRun();

// ---------------------------------------------------------------------------------------------------------------------------------
// Helper locals and macros to make this fine code thread-safe
// ---------------------------------------------------------------------------------------------------------------------------------

static int setOwnerLocked = 0;

#ifdef WIN32

static bool criticalSectionInitialized = false;
static CRITICAL_SECTION mmgrCriticalSection;

// Lock class. While an instance of this objects exists, the corresponding
// critical section will be locked
class CCriticalSectionLock
{
public:
CCriticalSectionLock(CRITICAL_SECTION* criticalSection)
{
m_criticalSection = criticalSection;
EnterCriticalSection(m_criticalSection);
}

~CCriticalSectionLock()
{
LeaveCriticalSection(m_criticalSection);
}
private:
CRITICAL_SECTION* m_criticalSection;
};

// This macro will be added to all functions which can be called from outside this file.
#define LOCK if (!criticalSectionInitialized) { InitializeCriticalSection(&mmgrCriticalSection); criticalSectionInitialized = true; } CCriticalSectionLock lock(&mmgrCriticalSection);

#define LOCKPERSISTENT if (!criticalSectionInitialized) { InitializeCriticalSection(&mmgrCriticalSection); criticalSectionInitialized = true; } EnterCriticalSection(&mmgrCriticalSection);
#define UNLOCK LeaveCriticalSection(&mmgrCriticalSection);
#else
// This macro will be added to all functions which can be called from outside this file.
#define LOCK
#define LOCKPERSISTENT
#define UNLOCK
#endif

// ---------------------------------------------------------------------------------------------------------------------------------
// Local functions only
// ---------------------------------------------------------------------------------------------------------------------------------

static void log(const char *format, ...)
{
// Cleanup the log?

if (cleanupLogOnFirstRun) doCleanupLogOnFirstRun();

// Build the buffer

static char buffer[2048];
va_list ap;
va_start(ap, format);
vsprintf(buffer, format, ap);
va_end(ap);

// Open the log file

FILE *fp = fopen(memoryLogFile, "ab");

// If you hit this assert, then the memory logger is unable to log information to a file (can't open the file for some
// reason.) You can interrogate the variable 'buffer' to see what was supposed to be logged (but won't be.)
m_assert(fp);

if (!fp) return;

// Spit out the data to the log

fprintf(fp, "%s/r/n", buffer);
fclose(fp);
}

// ---------------------------------------------------------------------------------------------------------------------------------

static void doCleanupLogOnFirstRun()
{
if (cleanupLogOnFirstRun)
{
unlink(memoryLogFile);
cleanupLogOnFirstRun = false;

// Print a header for the log

time_t t = time(NULL);
log("--------------------------------------------------------------------------------");
log("");
log(" %s - Memory logging file created on %s", memoryLogFile, asctime(localtime(&t)));
log("--------------------------------------------------------------------------------");
log("");
log("This file contains a log of all memory operations performed during the last run.");
log("");
log("Interrogate this file to track errors or to help track down memory-related");
log("issues. You can do this by tracing the allocations performed by a specific owner");
log("or by tracking a specific address through a series of allocations and");
log("reallocations.");
log("");
log("There is a lot of useful information

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 6
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值