2

I have written a managed class that wraps around an unmanaged C++ object, but I found that - when using it in C# - the GC kicks in early while I'm executing a method on the object. I have read up on garbage collection and how to prevent it from happening early. One way is to use a "using" statement to control when the object is disposed, but this puts the responsibility on the client of the managed object. I could add to the managed class:

MyManagedObject::MyMethod() {

System::Runtime::InteropServices::GCHandle handle =
   System::Runtime::InteropServices::GCHandle::Alloc(this);

// access unmanaged member

handle.Free();

}

This appears to work. Being new to .NET, how do other people deal with this problem?

Thank you,

Johan

Johan
  • 51
  • 3
  • 1
    the GC won't kick if something has a reference to your object....I think perhaps something else funky is happening with your orginal code. – Keith Nicholas Apr 27 '10 at 21:48
  • What does the C# code look like that is using this object? – Brad Cunningham Apr 27 '10 at 21:55
  • I read this article: http://blogs.msdn.com/cbrumme/archive/2003/04/19/51365.aspx If I do: MyManagedObject obj = new MyManagedObject(); obj.MyMethod(); Then obj can be (and is in my case) garbage collected whilst MyMethod is executing, unless the compiler can detect that MyMethod is accessing members of MyManagedObject. Unfortunately, MyMethod is merely accessing unmanaged code in my case, so the GC happily ignores this and disposes my object whilst executing MyMethod. – Johan Apr 27 '10 at 21:58
  • The `using` statement has nothing to do with GC. It calls `IDispose.Dispose` which is just another method as far as .Net is concerned. Although it is common for `Dispose` to interact with the GC, this is merely to suppress finalization (since Dispose is doing the finalization). – Marcelo Cantos Apr 27 '10 at 22:03
  • My point about the "using" statement is that it prevents the object from being finalised during execution of MyMethod. Is this the best way to achieve this though? – Johan Apr 27 '10 at 22:08
  • @Johan, (minor point of etiquette: if you have more information to add, add it to the question.) What you are describing sounds very odd and Keith's original comment still holds. You are clearly holding a reference (`obj`) to the managed wrapper in the calling code. It shouldn't matter what `MyMethod` does. – Marcelo Cantos Apr 27 '10 at 22:09
  • @Johan, and my (implied) point was that `using` doesn't suppress finalisation, it's the fact that a reference to the object exists that suppresses it. – Marcelo Cantos Apr 27 '10 at 22:11
  • @Keith, Marcelo, Thanks for the info. I thought too that as long as you have a reference to an object, it won't be disposed of. However, according to the mentioned article, the GC may kick in sooner depending on how liveness is determined. In my case, the garbage collector kicks while I'm invoking MyMethod, because it doesn't realise that MyMethod is accessing unmanaged code. If I add a dummy managed member to MyManagedObject and access that in MyMethod, the GC is delayed. – Johan Apr 27 '10 at 22:25

2 Answers2

3

You might like to take a look at this article: http://www.codeproject.com/Tips/246372/Premature-NET-garbage-collection-or-Dude-wheres-my. I believe it describes your situation exactly. In short, the remedies are either ausing block or a GC.KeepAlive. However, I agree that in many cases you will not wish to pass this burden onto the client of the unmanaged object; in this case, a call to GC.KeepAlive(this) at the end of every wrapper method is a good solution.

Phil Atkin
  • 33
  • 4
2

You can use GC.KeepAlive(this) in your method's body if you want to keep the finalizer from being called. As others noted correctly in the comments, if your this reference is not live during the method call, it is possible for the finalizer to be called and for memory to be reclaimed during the call.

See http://blogs.microsoft.co.il/blogs/sasha/archive/2008/07/28/finalizer-vs-application-a-race-condition-from-hell.aspx for a detailed case study.

Sasha Goldshtein
  • 3,499
  • 22
  • 35
  • Sasha, unfortunately your blog post is 404, I could find a cached version though. I had an [issue](https://stackoverflow.com/questions/56405624/when-gc-keepalivethis-is-needed-when-doing-p-invoke-on-unmanaged-resources) that hitted very hard and clearly needed to be solved with `GC.KeepAlive(this)`. Still, the question is if `GC.KeepAlive(this)` is actually needed everywhere, as you seem to point in your blog. Are you really sure? Can the GC collect an object in the current thread in the middle of P/Invoke when the execution context is unamanged (native code)? Can you comment on my issue? – ceztko Jun 01 '19 at 10:25