Mail Archives: cygwin/2002/09/14/16:58:24
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 <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/
- Raw text -