[Graph Libraries] Memory Leak between gvLayout() and gvFreeLayout()
Ported Issue from Mantis Original ID: 2094 Reported By: GaryM
SEVERITY: IMPORTANT Submitted: 2011-05-28 14:18:16
OS: WINDOWS VISTA
PLATFORM: PC
DESCRIPTION
There are easily reproducible memory leaks between gvLayout() and gvFreeLayout() when using GraphViz as a library on the PC.
STEPS TO REPRODUCE
// GViz_02_Mem_Layout.cpp : Defines the entry point for the console application.
//
#define NOMINMAX
#define VC_EXTRALEAN
#define WIN32_LEAN_AND_MEAN
#include <Windows.h>
#include <tchar.h>
#include <limits.h>
#include <conio.h>
#include <stdio.h>
#include <psapi.h> // Add "Psapi.lib" to import library
#include "..\..\Common_Third_Party\Graphviz\include\graphviz\gvc.h"
int _tmain(int argc, _TCHAR* argv[])
{
//--------------------------------------------------------------------
PROCESS_MEMORY_COUNTERS pmc;
DWORD processID = GetCurrentProcessId();
HANDLE hProcess;
// Print the process identifier.
printf( "\nProcess ID: %u\n", processID );
// Get the Process Handle
hProcess = OpenProcess( PROCESS_QUERY_INFORMATION |
PROCESS_VM_READ,
FALSE, processID );
//--------------------------------------------------------------------
Agraph_t *g;
Agraph_t *sg;
Agnode_t *n, *m;
Agedge_t *e;
Agsym_t *a;
GVC_t *gvc;
int loop;
if (argc < 2) {
fprintf (stderr, "Usage: mg <cnt>\n");
exit (1);
}
loop = atoi(argv[1]);
fprintf (stderr, "loop = %d\n", loop);
/* set up a graphviz context */
gvc = gvContext();
//---------------------------------------------------------------------- _tprintf( (TCHAR*)&_T("Layout Create and Destroy: Memory Working Set Change\n"));
long lng_Mem_Wrk_Curr = 0;
long lng_Mem_Wrk_Chnge = 0;
long lng_Mem_Wrk_Start = 0;
long lng_Mem_Wrk_Final = 0;
long lng_Mem_Wrk_Static = 0;
long lng_KByte = 1024;
float fPercent = 0.0f;
GetProcessMemoryInfo( hProcess, &pmc, sizeof(pmc));
lng_Mem_Wrk_Curr = pmc.WorkingSetSize;
lng_Mem_Wrk_Start = pmc.WorkingSetSize;
//---------------------------------------------------------------------- BOOL bFirst = FALSE;
int nCount = 0;
_tprintf( (TCHAR*)&_T("Cnt\t Change\n"));
/* Create a simple digraph */
g = agopen("g", AGDIGRAPH);
n = agnode(g, "n");
m = agnode(g, "m");
e = agedge(g, n, m);
sg = agsubg (g, "subg");
aginsert (sg, e);
/* Set an attribute - in this case one that affects the visible rendering */
agsafeset(n, "color", "red", "");
while ( nCount < loop ) {
gvLayout (gvc, g, "dot");
gvRender (gvc, g, "dot", NULL);
/* Free layout data */
gvFreeLayout(gvc, g);
GetProcessMemoryInfo( hProcess, &pmc, sizeof(pmc));
lng_Mem_Wrk_Chnge = (long)pmc.WorkingSetSize - lng_Mem_Wrk_Curr;
if( nCount == 0 ){
lng_Mem_Wrk_Static = lng_Mem_Wrk_Chnge;
}
_tprintf( (TCHAR*)&_T("%d\t%d kb\n"),
nCount,
(int)(lng_Mem_Wrk_Chnge/lng_KByte));
lng_Mem_Wrk_Curr = (long)pmc.WorkingSetSize;
nCount++;
}
/* Free graph structures */
agclose(g);
/* close output file, free context, and return number of errors */
int nRes = (gvFreeContext(gvc));
EmptyWorkingSet( hProcess );
GetProcessMemoryInfo( hProcess, &pmc, sizeof(pmc));
lng_Mem_Wrk_Final = pmc.WorkingSetSize;
int mMem_Wrk_Start_To_Finish = (int)((lng_Mem_Wrk_Final - lng_Mem_Wrk_Start)/lng_KByte);
int nMem_Wrk_Exclude_Static = (int)((lng_Mem_Wrk_Final - lng_Mem_Wrk_Start - lng_Mem_Wrk_Static)/lng_KByte);
_tprintf( (TCHAR*)&_T("Mem Gain Total\t\t%d kb\n"), mMem_Wrk_Start_To_Finish );
_tprintf( (TCHAR*)&_T("Mem Gain Excl One-Off\t%d kb\n"), nMem_Wrk_Exclude_Static );
_tprintf( (TCHAR*)&_T("Mem Gain Avg\t\t%d kb\n\n"), (nMem_Wrk_Exclude_Static * lng_KByte)/(int)loop );
_tprintf( (TCHAR*)&_T("Press any key to Exit.\n") );
_getch();
//-------------------------------------------------------------
CloseHandle( hProcess );
//-------------------------------------------------------------
return nRes;
}