Mailing-List: contact cygwin-help AT cygwin DOT com; run by ezmlm List-Subscribe: List-Archive: List-Post: List-Help: , Sender: cygwin-owner AT cygwin DOT com Mail-Followup-To: cygwin AT cygwin DOT com Delivered-To: mailing list cygwin AT cygwin DOT com Message-ID: <3D839884.D211C44E@iee.org> Date: Sat, 14 Sep 2002 21:13:56 +0100 From: Don Sharp X-Accept-Language: en MIME-Version: 1.0 To: gnuwin32 Subject: Re: Memory Leak - DLL problem References: <20020914194429 DOT 961 DOT qmail AT web10003 DOT mail DOT yahoo DOT com> Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Tirth Sanyal wrote: > > Hi, > > I have been encountering a strange memory leak problem > in my code which has prompted me to write a small > program to isolate and demonstrate it. I have pasted > the code at the bottom of the email. > > Please cc your replies to tsanyal AT yahoo DOT com > > Here is the problem: > Platform - Windows 2000 SP3, Cygwin, gcc - 2.95.3-5 > > - In a DLL say libfoo, I define and export a class > Base and also export a function "foo" whose interface > is the following: > Base* foo(void) > > - "foo" instantiates an object of the class Base and > returns a pointer to this object. > > - In my application (which has the main routine) I > load the dynamic library libfoo, call function "foo" > in it , get the pointer to the newly created object > and immediately call "delete" on this pointer. > > - The destructor function of the class Base contained > in the libfoo DLL is called. > > - This is done about 2 million times. > > - However, when I see the memory usage, it rises to > about 32MB and stays there... it never goes down which > clearly indicates that the memory is not being freed. > > - I have also created another test program which does > not involve any dynamic loading of libraries. This is > a self contained monolithic program which defines and > implements the class in the same file. > > - Instantiation and destruction of class Base objects > are done 2 million times in this program as well. > > - The memory consumption is only a meagre 1 MB. > > This indicates that there is a problem with the > freeing of memory corresponding to objects when > classes are exported in a DLL. > > I would appreciate it if you could share your ideas > regarding this matter. > Our experience at work is that memory allocated in a dll has to be freed by the same dll otherwise you get this sort of memory leakage. We have a single dll that does all the allocations and freeing of memory because of this. HTH Don Sharp > Thanks in advance. > -Tirth > > CODE - pasted ( foo.hpp , foo.cpp , main.cpp) > Followed by (main.hpp and main.cpp of the monolithic > program) > ------------------------------------------------------- > > libfoo - DLL > > foo.hpp > > /* Only include this header file once. */ > #ifndef _FOO_H_ > #define _FOO_H_ 1 > > #include > #ifdef EXTERN_FOO > #undef EXTERN_FOO > #endif > > # ifdef _LIBFOO_COMPILATION_ > # define EXTERN_FOO __declspec(dllexport) > # else > # define EXTERN_FOO __declspec(dllimport) > # endif > > extern "C" { > class EXTERN_FOO Base { > public: > char* str; > Base(void); > ~Base(void); > }; > > EXTERN_FOO Base* foo (void); > } > > #endif /* !_FOO_H_ */ > > ------------------------------------------------------- > foo.cpp > > #if HAVE_CONFIG_H > # include > #endif > > #define _LIBFOO_COMPILATION_ > # include "foo.hpp" > #undef _LIBFOO_COMPILATION_ > > #include > #include > > EXTERN_FOO Base::Base(void) > { > str = (char*) malloc(1000); > } > > EXTERN_FOO Base::~Base() > { > if (str) { > free(str); > printf("Deleted the base Object\n"); > } > } > > Base* > foo(void){ > Base* base = NULL; > > base = new Base(); > printf("foo:Created a base Object\n"); > > return (base); > } > > ------------------------------------------------------ > > APPLICATION > > main.cpp > > #include > #include > #include > #include > #include > #ifndef EXIT_FAILURE > # define EXIT_FAILURE 1 > # define EXIT_SUCCESS 0 > #endif > > #include > #ifndef PATH_MAX > # define PATH_MAX 255 > #endif > > #include > /* This is missing from very old Linux libc. */ > #ifndef RTLD_NOW > # define RTLD_NOW 2 > #endif > > typedef Base* entrypoint (); > //typedef u_char* entrypoint (); > > /* Save and return a copy of the dlerror() error > message, > since the next API call may overwrite the original. > */ > static char *dlerrordup (char *errormsg); > > int > main (int argc, char *argv[]) > { > char modulepath[1+ PATH_MAX] = ""; > char *errormsg = NULL; > void *module = NULL; > entrypoint *run = NULL; > int errors = 0; > int result = 0; > int i = 0; > char* j = NULL; > Base* base = NULL; > // u_char* base = NULL; > > printf("---------------------------------------------------------------\n\n"); > > if (argc != 2) > { > fprintf (stderr, "USAGE: newtest MODULENAME > \n"); > exit (EXIT_FAILURE); > } > > /* Set the module search path. */ > strcat (modulepath, "/usr/local/lib/"); > strcat (modulepath, argv[1]); > > printf("Modulepath is : %s\n",modulepath); > > /* Load the module. */ > printf("Loading module %s........",argv[1]); > module = dlopen (modulepath, RTLD_NOW | > RTLD_GLOBAL); > > if (!module) > { > errors = 1; > printf("Failed to load module\n"); > } > > /* Find the entry point. */ > if (!errors) > { > printf("loaded\n"); > printf("Finding entry point for 'foo'........"); > run = (entrypoint*) dlsym (module, "foo"); > /* In principle, run might legitimately be NULL, > so > I don't use run == NULL as an error > indicator. */ > errormsg = dlerrordup (errormsg); > > if (errormsg != NULL) > errors = dlclose (module); > else > printf("found\n"); > } > > /* Call the entry point function. */ > if (!errors) > { > printf("Calling entry point function > 'foo'........\n"); > > for (i = 0; i < 2000000; i++){ > base = (*run) (); > if(!base) > errormsg = strdup ("module entry point > execution failed"); > > delete (base); > } > } > > /* Unload the module, now that we are done with it. > */ > if (!errors) > errors = dlclose (module); > > if (errors) > { > /* Diagnose the encountered error. */ > errormsg = dlerrordup (errormsg); > > if (!errormsg) > { > fprintf (stderr, "%s: dlerror() failed.\n", > argv[0]); > return EXIT_FAILURE; > } > } > > printf("Terminating demo\n"); > > if (errormsg) > { > fprintf (stderr, "%s: %s.\n", argv[0], > errormsg); > free (errormsg); > return EXIT_FAILURE; > } > > sleep(20); > return EXIT_SUCCESS; > } > > /* Be careful to save a copy of the error message, > since the next API call may overwrite the original. > */ > static char * > dlerrordup (char *errormsg) > { > char *error = (char *) dlerror (); > if (error && !errormsg) > errormsg = (char*) strdup (error); > return errormsg; > } > > ------------------------------------------------------- > > Monolithic example > main.hpp > > #ifndef _MAIN_HPP_ > #define _MAIN_HPP_ 1 > > class Base { > public: > char* str; > // int i; > Base(void); > virtual ~Base(void); > }; > > class Derived: public Base { > public: > Derived(void); > virtual ~Derived(void); > }; > > #endif > > ------------------------------------------------------- > main.cpp > > #include > #include > #include > #include > > #include "main.hpp" > > Base::Base() > { > str = (char*) malloc(1000); > } > Base::~Base() > { > if(str) > free(str); > } > > Derived::Derived() > { > } > > Derived::~Derived() > { > } > > int > main (int argc, char *argv[]) > { > Base* base = NULL; > // u_char* derived = NULL; > int i = 0; > > for(i=0;i<20000000;i++){ > base = new Base(); > // derived = (u_char*) new Derived(); > printf("Object created\n"); > > delete(base); > // delete((Base*) derived); > printf("Object deleted\n"); > } > > sleep(20); > return 1; > > } > ---------------------END------------------------------ > > __________________________________________________ > Do you Yahoo!? > Yahoo! News - Today's headlines > http://news.yahoo.com > > -- > Unsubscribe info: http://cygwin.com/ml/#unsubscribe-simple > Bug reporting: http://cygwin.com/bugs.html > Documentation: http://cygwin.com/docs.html > FAQ: http://cygwin.com/faq/ -- Unsubscribe info: http://cygwin.com/ml/#unsubscribe-simple Bug reporting: http://cygwin.com/bugs.html Documentation: http://cygwin.com/docs.html FAQ: http://cygwin.com/faq/