You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

398 lines
8.8 KiB
C++

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

/************************************************************************
*
* Copyright (C) 2003-2004
* Shenzhen SCADA Control Technology Co., Ltd.
* All rights reserved.
*
* 用于调试内存泄漏的对内存分配函数的实现
*
* 创建日期: 2005/04/12
*
***********************************************************************/
/*#ifdef OS_LINUX
#include <sys/types.h>
#include <sys/time.h>
#endif*/
#include <stdio.h>
#include <stdlib.h>
#include <memory.h>
#include <string.h>
#include <errno.h>
#include "time.h"
#include "list_entry.h"
#include "os_heap.h"
#if defined(_WIN32)
#include <winsock2.h>
#include <direct.h>
#include <process.h>
#endif
#ifdef _fclose
#undef _fclose
#endif
#define _fclose(_fp) do {if (_fp) {while (EOF == fclose((_fp)) && EINTR == errno);}} while(0)
/*!
* 堆内存块的类型
*/
typedef enum {
eMalloc = 0, /* 使用malloc分配的内存块 */
eCalloc = 1 /* 使用calloc分配的内存块 */
} heap_type_t;
/*!
* 堆内存块附加头
*
* \note
* 必须保证本结构的尺寸被16整除。
*/
typedef struct tag_heap_head_t {
/* 堆内存块附加头所在的链表的占位 */
list_entry_t anchor;
/*! 堆内存块分配发生的时间 */
struct timeval tv;
/*! 堆内存块类型 */
heap_type_t type;
/*! 堆内存块分配发生的源文件名NULL表示匿名源文件。 */
char * fl;
/*! 堆内存块分配发生的源代码行 */
int line;
/*! 堆内存块的尺寸(字节) */
size_t size;
} heap_list_t;
/* 边界对齐量 */
#define os_heap_alignment 16
#define os_heap_pad ((sizeof(heap_list_t) % os_heap_alignment) ? (os_heap_alignment - (sizeof(heap_list_t) % os_heap_alignment)) : 0)
/* 根据数据地址求os_heap块的起始地址 */
#define os_heap_start_addr(_data) ((void *)(((unsigned char *)(_data)) - sizeof(heap_list_t) - os_heap_pad))
/* 根据os_heap块的起始地址求数据地址 */
#define os_heap_data_addr(_start) ((void *)(((unsigned char *)(_start)) + sizeof(heap_list_t) + os_heap_pad))
/* 根据数据块的尺寸求os_heap块的尺寸 */
#define os_heap_mb_size(_size) (sizeof(heap_list_t) + os_heap_pad + (_size))
/*
* 内存管理模块:
*
* 1. 初始化过程
* 2. 具有一个私有线程,专门侦听外部的信号,并打印报告。
* 3. 堆内存块链表头、尾指针。
* 4. 互斥访问保护
*/
/* 堆内存块设施是否已经初始化 */
static int g_heap_initialized = 0;
/* 堆内存块双向链表头 */
static list_entry_t g_heap_head;
/*
* 进程中使用heap_malloc/heap_calloc分配的内存
* 且现在还在使用的内存块的总数。
*/
static size_t g_heap_item_counter = 0;
/*
* 进程中使用heap_malloc/heap_calloc分配的内存
* 且现在还在使用的总量(字节)
*/
static size_t g_heap_byte_counter = 0;
/* 初始化堆内存块设施 */
static void heap_intialize();
/*!
* \brief 堆内存分配
*
* \param size 希望分配的内存的尺寸
* \param file 指向发生堆内存分配的源代码文件名称以null字符结尾。
* 如果等于NULL 表示匿名源代码文件名(anony)
* \param line 发生堆内存分配的源代码行号
*
* \retutrn
* 对内存分配成功的情况下,返回指向分配的内存的指针。如果内存
* 分配失败返回NULL。
*
* \note
* 当分配的内存不在使用时必须调用heap_free是否分配的内存。
*
* 参见 ANSI C 函数 malloc。
*/
void * heap_malloc (
size_t size,
const char * file,
int line )
{
// #ifdef DISABLE_OS_HEAP
return malloc(size);
/*#else /* #ifdef DISABLE_OS_HEAP */
/*
struct timeval tv;
char * fl = NULL;
void * mb = NULL;
heap_list_t * hl = NULL;
if (0 == size)
return NULL;
if (file) {
fl = (char *)malloc(strlen(file) + 4);
if (fl) strcpy (fl, file);
}
gettimeofday(&tv, NULL);
mb = malloc(os_heap_mb_size(size));
if (NULL == mb) {
if (fl) free (fl);
return mb;
} else {
memset (mb, 0, os_heap_mb_size(size));
}
hl = (heap_list_t *)mb;
hl->type = eMalloc;
hl->tv = tv;
hl->fl = fl;
hl->line = line;
hl->size = size;
if (!g_heap_initialized) {
heap_intialize();
g_heap_initialized = 1;
}
insert_tail_list (&g_heap_head, &(hl->anchor));
g_heap_item_counter++;
g_heap_byte_counter += hl->size;
return os_heap_data_addr(hl);
#endif *//* #ifdef DISABLE_OS_HEAP */
}
/*!
* \brief 堆内存分配, 且内存块被初始化0.
*
* \param num 内存块个数
* \param elm_size 每一个内存块的尺寸(字节)
* \param file 指向发生堆内存分配的源代码文件名称以null字符结尾。
* 如果等于NULL 表示匿名源代码文件名(anony)
* \param line 发生堆内存分配的源代码行号
*
* \retutrn
* 对内存分配成功的情况下,返回指向分配的内存的指针。如果内存
* 分配失败返回NULL。
*
* \note
* 当分配的内存不在使用时必须调用heap_free释放分配的内存。
*
* 参见 ANSI C 函数 calloc。本函数与 calloc 不同之处在于不能
* 象calloc那样保证返回的堆内存块的其实地址对齐在elm_size边界
* 上。
*/
void * heap_calloc (
size_t num,
size_t elm_size,
const char * file,
int line )
{
//#ifdef DISABLE_OS_HEAP
return calloc(num, elm_size);
//#else /* #ifdef DISABLE_OS_HEAP */
/* struct timeval tv;
char * fl = NULL;
void * mb = NULL;
heap_list_t * hl = NULL;
if (0 == num * elm_size)
return NULL;
if (file) {
fl = (char *)malloc(strlen(file) + 4);
if (fl) strcpy (fl, file);
}
gettimeofday(&tv, NULL);
mb = malloc(os_heap_mb_size(elm_size * num));
if (NULL == mb) {
if (fl) free (fl);
return mb;
} else {
memset (mb, 0, os_heap_mb_size(elm_size * num));
}
hl = (heap_list_t *)mb;
hl->type = eCalloc;
hl->tv = tv;
hl->fl = fl;
hl->line = line;
hl->size = elm_size * num;
if (!g_heap_initialized) {
heap_intialize();
g_heap_initialized = 1;
}
insert_tail_list (&g_heap_head, &(hl->anchor));
g_heap_item_counter++;
g_heap_byte_counter += hl->size;
return os_heap_data_addr(hl);
#endif *//* #ifdef DISABLE_OS_HEAP */
}
/*!
* \brief 释放堆内存
*
* \param memblock 指向先前调用heap_alloc/heap_calloc分配的内存。
*
* \return
* 无。
*/
void heap_free (void * mb)
{
#ifdef DISABLE_OS_HEAP
free (mb);
#else /* #ifdef DISABLE_OS_HEAP */
size_t sz = 0;
heap_list_t * hl = NULL;
if (NULL == mb)
return;
if (!g_heap_initialized) {
heap_intialize();
g_heap_initialized = 1;
return;
}
hl = (heap_list_t *)os_heap_start_addr(mb);
#if defined(WIN32) && (defined(DEBUG) || defined(_DEBUG))
if (IsBadReadPtr((void *)hl, sizeof(heap_list_t))) {
return;
}
if (IsBadReadPtr((void *)hl, os_heap_mb_size(hl->size))) {
return;
}
#endif
remove_entry_list (&(hl->anchor));
sz = hl->size;
if (hl->fl)
free ((void *)(hl->fl));
free ((void *)hl);
g_heap_item_counter--;
g_heap_byte_counter -= sz;
#endif /* #ifdef DISABLE_OS_HEAP */
}
/*!
* \brief 报告堆内存分配
*
* 调用本函数将堆内存分配情况以追加的方式输出到指定文件中。
*
* \param fname 对内存分配报告将输出到该文件中。如果fname等于NULL
* 则报告将输出到标准输出上。
*
* \retval -1 函数调用失败。
* \retval 0 函数调用成功。
*
* \note
* 报告的格式如下
* 时间:
* 内存使用总量:
* ......
* 内存块列表i:
* 时间: tv
* 类型: malloc/calloc,
* 源码位置: fl(line)
* 尺寸: size
* ......
*/
int heap_report(const char * fname)
{
/* #ifndef DISABLE_OS_HEAP
int i = 0;
FILE * fp = NULL;
heap_list_t * hl = NULL;
list_entry_t * item = NULL;
list_entry_t * first = NULL;
list_entry_t * next = NULL;
char szdt[32];
if (fname) {
fp = fopen (fname, "a+t");
if (NULL == fp)
return -1;
} else
fp = stdout;
if (!g_heap_initialized) {
heap_intialize();
g_heap_initialized = 1;
if (fname) _fclose(fp);
return 0;
}
fprintf (fp, "\n"
"heap allocation summary...\n"
"time: %s\n"
"heap_item_counter: %u\n"
"heap_byte_counter: %u(bytes)\n",
cur_tm_string (szdt),
g_heap_item_counter,
g_heap_byte_counter);
first = &g_heap_head;
for ( next = first->flink; next != first; next = next->flink )
{
item = next;
hl = CONTAINING_RECORD ( item, heap_list_t, anchor );
fprintf (fp, " heap block %d:"
" times: %s"
" type: %s"
" size: %08u (bytes)"
" source: %s [%d]\n",
i++, timeval_string(&(hl->tv), szdt),
(eMalloc == hl->type ? "malloc" : "calloc"),
hl->size, (hl->fl ? hl->fl : "nony"), hl->line);
}
if (fname) _fclose(fp);
#endif*/
return 0;
}
static void heap_intialize()
{
Initialize_list_head (&g_heap_head);
}