📄 memwatch.c
字号:
/* This file was contributed by Peter Selinger and is copyrighted under the GNU General Public License. *//* The purpose of this file is to define alternative "malloc", "realloc", and "free" macros (together with some friends, such as "strdup"), for the purpose of detecting memory leaks. This is a debugging tool, and is disabled by default. *//* this code monitors *other* code's memory usage, not its own! */#define _GNU_SOURCE /* needed for stdio.h:vasprintf */#include <stdio.h>#include <sys/time.h>#include <stdlib.h>#include <string.h>#include <stdarg.h>#include <time.h>#include "lists.h"#include "alias.h"struct memwatch_s { char *file; int line; struct timeval tv; void *p; size_t size; int tag; struct memwatch_s *next;};typedef struct memwatch_s memwatch_t;memwatch_t *memlist=NULL;void memlog(char *fmt, ...) { va_list args; char buf[100]; FILE *f; va_start(args, fmt); vsprintf(buf, fmt, args); va_end(args); f = fopen("memory.log", "a"); if (f) { fputs(buf, f); fclose(f); }}char *ttoa(struct timeval *tv) { static char buf[100]; sprintf(buf, "%lds+%6ldms", tv->tv_sec, tv->tv_usec); return buf;} void *memwatch_malloc(size_t size, char *file, int line) { void *p; memwatch_t *m; struct timeval tv; gettimeofday(&tv, NULL); p = malloc(size); if (!p) { memlog("%s:%d: malloc(%d) returned 0 (%s)\n", file, line, size, ttoa(&tv)); return NULL; } m = malloc(sizeof(memwatch_t)); m->file = file; m->line = line; m->tv.tv_sec = tv.tv_sec; m->tv.tv_usec = tv.tv_usec; m->p = p; m->size = size; m->tag = 0; list_prepend(memlist, m); if (nvar_default("memwatchverbose",0)) { memlog("%s:%d: malloc(%d) returned %p (%s)\n", file, line, size, p, ttoa(&tv)); } return p;}void memwatch_free(void *p, char *file, int line) { memwatch_t *m; memwatch_t **hook; struct timeval tv; if (p!=NULL) { gettimeofday(&tv, NULL); list_find2(m, memlist, m->p == p, hook); if (m==NULL) { memlog("%s:%d: bad free(%p) (%s)\n", file, line, p, ttoa(&tv)); return; } list_unlink_athook(memlist, m, hook); free(m); free(p); if (nvar_default("memwatchverbose",0)) { memlog("%s:%d: free(%p) (%s)\n", file, line, p, ttoa(&tv)); } }}void *memwatch_realloc(void *p, size_t size, char *file, int line) { void *q; memwatch_t *m; memwatch_t **hook; struct timeval tv; gettimeofday(&tv, NULL); if (p!=NULL) { list_find2(m, memlist, m->p == p, hook); if (m==NULL) { memlog("%s:%d: bad realloc(%p, %d) (%s)\n", file, line, p, size, ttoa(&tv)); return NULL; } list_unlink_athook(memlist, m, hook); } else { m = malloc(sizeof(memwatch_t)); } q = realloc(p, size); if (!q) { memlog("%s:%d: realloc(%p, %d) returned 0 (%s)\n", file, line, p, size, ttoa(&tv)); return NULL; } m->file = file; m->line = line; m->tv.tv_sec = tv.tv_sec; m->tv.tv_usec = tv.tv_usec; m->p = q; m->size = size; m->tag = 0; list_prepend(memlist, m); if (nvar_default("memwatchverbose",0)) { memlog("%s:%d: realloc(%p, %d) returned %p (%s)\n", file, line, p, size, q, ttoa(&tv)); } return q;} char *memwatch_strdup(const char *s, char *file, int line) { char *p; memwatch_t *m; struct timeval tv; gettimeofday(&tv, NULL); if (!s) { memlog("%s:%d: bad strdup(%p) (%s)\n", file, line, s, ttoa(&tv)); return NULL; } p = strdup(s); if (!p) { memlog("%s:%d: strdup(%p) returned 0 (%s)\n", file, line, s, ttoa(&tv)); return NULL; } m = malloc(sizeof(memwatch_t)); m->file = file; m->line = line; m->tv.tv_sec = tv.tv_sec; m->tv.tv_usec = tv.tv_usec; m->p = p; m->size = strlen(s)+1; m->tag = 0; list_prepend(memlist, m); if (nvar_default("memwatchverbose",0)) { memlog("%s:%d: strdup(%p) returned %p (%s)\n", file, line, s, p, ttoa(&tv)); } return p;}int memwatch_vasprintf(char **strp, const char *fmt, va_list ap, char *file, int line) { int r; memwatch_t *m; struct timeval tv; gettimeofday(&tv, NULL); if (*strp != NULL) { memlog("%s:%d: warning: passing non-null pointer to vasprintf() (%s)\n", file, line, ttoa(&tv)); } r = vasprintf(strp, fmt, ap); if (r == -1) { memlog("%s:%d: vasprintf() returned -1 (%s)\n", file, line, ttoa(&tv)); return -1; } m = malloc(sizeof(memwatch_t)); m->file = file; m->line = line; m->tv.tv_sec = tv.tv_sec; m->tv.tv_usec = tv.tv_usec; m->p = *strp; m->size = strlen(*strp)+1; m->tag = 0; list_prepend(memlist, m); if (nvar_default("memwatchverbose",0)) { memlog("%s:%d: vasprintf() allocated %p (%s)\n", file, line, *strp, ttoa(&tv)); } return r;}/* clear all tags */void memwatch_cleartags() { memwatch_t *m; list_forall(m, memlist) { m->tag = 0; }}/* tag a cell */void memwatch_tag(void *p, int tag) { memwatch_t *m; struct timeval tv; if (!p) { return; } list_find(m, memlist, m->p == p); if (m==NULL) { gettimeofday(&tv, NULL); memlog("bad tag: %p %d (%s)\n", p, tag, ttoa(&tv)); return; } m->tag = tag;}/* log the current memory usage */void memwatch_dump() { memwatch_t *m; struct timeval tv; long age, uage; size_t size; int cells; int maxtag = 100; size_t size_tag[maxtag]; int cells_tag[maxtag]; int i; gettimeofday(&tv, NULL); memlog("----------------------------------------------------------------------\n"); memlog("Memory footprint at %s\n", ttoa(&tv)); cells = 0; size = 0; for (i=0; i<maxtag; i++) { size_tag[i] = 0; cells_tag[i] = 0; } list_forall(m, memlist) { size += m->size; cells += 1; size_tag[m->tag] += m->size; cells_tag[m->tag] += 1; age = tv.tv_sec - m->tv.tv_sec; uage = tv.tv_usec - m->tv.tv_usec; if (uage<0) { age -= 1; uage += 1000000; } memlog("%p size=[%4d] age=%ld.%06lds tag=%d created=%s:%d\n", m->p, m->size, age, uage, m->tag, m->file, m->line); } for (i=0; i<maxtag; i++) { if (cells_tag[i]) { memlog("Tag %d: %d cells, %d bytes\n", i, cells_tag[i], size_tag[i]); } } memlog("Total: %d cells, %d bytes\n", cells, size); memlog("----------------------------------------------------------------------\n");}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -