On Aug 24, 2012, at 1:11 PM, David Jeske <dav...@gmail.com> wrote:
> (1) Why would a call to an instance method not hold "this" alive for the 
> entire duration of the call? 

`this` isn't special, it's just an implicit variable passed into the method. If 
the variable isn't used within the method call, then it's collectible.

Rephrased, consider this:

        // caller:
        Foo (new StringBuilder ());

        // Implementation:
        static void Foo(StringBuilder b)
        {
                Thread.Sleep (1000);
        }

The variable `sb` isn't used at all within Foo(). Consequently, the 
StringBuilder instance can be collected at any time, and no one will notice (as 
far as the GC is concerned). (The StringBuilder allocation could be omitted 
entirely, actually, if the runtime environment were smart enough to determine 
that it wasn't doing anything...)

Since `this` is "just" a variable, the GC treats it in the same way. The issue 
isn't so much that the GC is treating P/Invoke specially; the issue is that 
it's not treating it specially at all, and P/Invoke introduces a "different 
world" (native code) which the GC doesn't know anything about. Consequently, 
the GC can (and will) collect instances that the GC knows are unreachable from 
managed code, but may still be referenced from native code.

> It seems this could happen in more cases than just PInvoke. This seems to 
> allow a finalizer to run before an object is "done being used" anytime the 
> object instance is not stored. (i.e. inside a statement of the form "new 
> Foo().Method();") If the finalizer triggers an IDispose pattern, this could 
> cause a managed resource to be torn down before it's done being used as well.

The managed resource can't be disposed before it's done being used AS LONG AS 
the GC knows about all uses of the managed resource.

In your `new Foo().Method()` example, it IS possible that the GC will finalize 
the `Foo` instance before Method() has returned, but it will only do so AS LONG 
AS `this` is no longer referenced within Method(). Thus, if Method() were empty 
or didn't use any instance members at all (e.g. the above Foo() body), then the 
instance can be collected while Method() is executing. Furthermore, it won't 
matter, as there's no way for Method() to even know that's happening.

The real problem is that the GC doesn't know anything about native code, and 
thus can't ensure that no native code is using the resource.

> Why isn't this considered a bug in the .NET runtime?

How would you fix it? The .NET runtime has no way of knowing what native code 
is doing, so short of disassembling the native code ("magic"), what is .NET 
supposed to do?

> (2) Does the Mono GC have the same behavior?

Yes, because there's no other sane behavior.

With Boehm it may be less of an issue, as Boehm is non-moving collector (so the 
memory won't be invalidated as quickly), and due to Boehm and Sgen's 
conservative stack walking nature Mono is more likely to preserve managed code 
which is referenced by native stack frames.

However, this can't be relied upon; Linux supports "precise stack marking," 
which prevents conservative scanning of native stack frames. This has the 
wonderful performance advantage that less memory needs to be pinned, allowing 
the GC to be more efficient:

        http://www.mono-project.com/Generational_GC#Precise_Stack_Marking

 - Jon

_______________________________________________
Mono-devel-list mailing list
Mono-devel-list@lists.ximian.com
http://lists.ximian.com/mailman/listinfo/mono-devel-list

Reply via email to