This is the mail archive of the
cygwin@cygwin.com
mailing list for the Cygwin project.
Memory Leak - DLL problem
- From: Tirth Sanyal <tsanyal at yahoo dot com>
- To: cygwin at cygwin dot com
- Cc: tsanyal at yahoo dot com
- Date: Sat, 14 Sep 2002 12:44:29 -0700 (PDT)
- Subject: Memory Leak - DLL problem
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.
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/