This is the mail archive of the cygwin@cygwin.com mailing list for the Cygwin project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: Memory Leak - DLL problem



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@yahoo.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 <sys/types.h>
> #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 <config.h>
> #endif
> 
> #define _LIBFOO_COMPILATION_
> #  include "foo.hpp"
> #undef _LIBFOO_COMPILATION_
> 
> #include <stdio.h>
> #include <stdlib.h>
> 
> 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 <foo.hpp>
> #include <stdio.h>
> #include <stdlib.h>
> #include <unistd.h>
> #include <string.h>
> #ifndef EXIT_FAILURE
> #  define EXIT_FAILURE        1
> #  define EXIT_SUCCESS        0
> #endif
> 
> #include <limits.h>
> #ifndef PATH_MAX
> #  define PATH_MAX 255
> #endif
> 
> #include <dlfcn.h>
> /* 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 <foo.h>
> #include <stdio.h>
> #include <stdlib.h>
> #include <unistd.h>
> 
> #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/


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]