• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 400
  • Last Modified:

Why does the destructor for my CLI/CPP ref class not get called (which results in a memory leak)?


I have some questions regarding use of gcnew and explicitly calling delete on the created object.
It appears that I have a leak in my code.

Consider the following example.

I have an unmanaged class:
public class FooBar
   int x;
   int y;

Open in new window

I have a managed class which wraps the unmanaged class:
ref class Foo
   private FooBar* pFooBar;

      pFooBar = new FooBar();

      delete pFooBar;
      pFooBar = nullptr;

Open in new window

I have  a method which returns a handle to the managed class to a .Net C# client:
public Foo^  GetMeAFoo()
   Foo^ foo = gcnew Foo();
   return foo;

Open in new window

It's my understanding that since Foo is created on the managed heap that I do not have to explicitly
delete it. Garbage Collection (GC) on the managed side should take care of it.
The problem in my case is that the destructor of my managed class never seems to get called.
The results in the interior pointer to my unmanaged class getting (memory) leaked.

What is the correct way to handle this situation so that the underlying unmanaged class (FooBar) gets
correctly freed (when the managed wrapper class goes out of scope)?

1 Solution
You're not deriving from IDisposable on the .NET side. That seems to be the problem to me...
Jacques Bourgeois (James Burger)PresidentCommented:
Managed code is managed in a very different way than unmanaged code is. There is no destructor on a managed class. There is a finalizer. And it is not called when the object goes out of scope, but when the GC requires resources. This could take hours and even days if the computer goes to sleep instead of being shutdown.

The standard in .NET managed classes that use unmanaged objects is to implements the IDisposable interface through a Dispose method that releases the unmanaged objects. This method should ideally be called by the application before the managed object variable goes out of scope in order to release the unmanaged objects.

When appropriate, create a Close method that calls Dispose. Close is more intuitive for some programmers who do not no about Dispose but are used to a Close method from previous experience. Look at classes such as SqlConnection and System.Windows.Forms, that have both. When you call Close, it calls Dispose, that releases the unmanaged resources.

And just in case the programmer who used your class did not care to call your method, also program the finalizer (Finalize method) to call Dispose so that the GC will eventually release everything.

Just lookup the documentation for IDisposable and Finalize for more details on how to deal with unmanaged objects used in your managed classes.
AndyAinscowFreelance programmer / ConsultantCommented:
>>when the managed wrapper class goes out of scope)?

The problem is probably a lack of understanding.  The garbage collector will call a destructor when the class is removed from memory.  However the GC mechanism does not remove a class from memory when it goes out of scope - it removes it from memory when the memory is required again or when the app is closed.  This is not what one expects compared to unmanaged code - you do not have a memory leak.
you may consider to putting the creation of unmanaged objects into unmanaged code. the managed class then would only hold a 'handle' of the unmanaged object.

typedef FooBar * FBHDL;
class UnmanagedFooBarHandler
      std::vector<FooBar*> allbars;
      // private constructor makes it a singleton
      UnmanagedFooBarHandler() {}
      ~UnmanagedFooBarHandler() { while (allbars.size()) { delete allbars[0]; allbars.erase(allbars.begin()); }}
      static UnmanagedFooBarHandler & UFBH() 
     { static UnmanagedFooBarHandler ufbh; return ufbh; }
     FBHDL createFooBar() { allbars.push_back(new FooBar()); return (FBHDL)allbars.back(); }
     void deleteFooBar(FBHDL fb) 
     { std::vector<FooBar*>::iterator f = std::find(allbars.begin(), allbars.end(), fb); 
       if (f != allbars.end()) { delete *f; allbars.erase(f); }

Open in new window

the managed class would create FooBar via handler.

FBHDL fb = UFBH().createFooBar();

Open in new window

and delete it after use.


Open in new window


jxbmaSoftware ConsultantAuthor Commented:
I added a finalize to the classes in question and all is well.
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

Join & Write a Comment

Featured Post

Cloud Class® Course: Amazon Web Services - Basic

Are you thinking about creating an Amazon Web Services account for your business? Not sure where to start? In this course you’ll get an overview of the history of AWS and take a tour of their user interface.

Tackle projects and never again get stuck behind a technical roadblock.
Join Now