On 24-05-2012 17:18, Michel Fortin wrote:
On 2012-05-24 14:35:45 +0000, Alex Rønne Petersen <a...@lycus.org> said:

On 24-05-2012 14:43, Michel Fortin wrote:
I think it means that objects not collected when the program terminates
will never be, and thus the destructor will not be called.

That's silly. Microsoft .NET and Mono have been running finalizers on
runtime shutdown for a long time without problems.

There's also the issue of false pointers that can prevent some objects
from being collected.

Right, but I think if we guarantee finalization at shutdown, that
shouldn't matter.

.NET is a virtual machine which has total control of all the code that
runs. D has to work with the C runtime and other non-D code that might
use D code more or less directly.

So does .NET. It just does it with some trampoline magic. Non-D code just has to call thread_attachThis()/thread_detachThis() and friends.


The interesting question is *how* do they do it without causing
thread-safety issues? Perhaps they wait until all threads have been
terminated, or perhaps they're unsafe too. Would doing the same be
appropriate for D? Does this mean we can't use anything using static and
global variables in destructors because they might have been finalized?
If so, how does the compiler detects this?

The CLR waits for all threads to have shut down (including daemon threads). That's not equal to all static/__gshared data being nulled out, mind you. All data is cleared out once all threads, including the finalizer thread, have been terminated one way or another.

And yes, it is thread safe.


If there's a way and it is not overly costly in performance, it might be
a good idea. But we're not in a virtual machine, there are more
constrains we must abide to and we might have to make different
compromises.

Don't need a virtual machine. We already have the infrastructure to do it in druntime, we just need to make the lifetime and GC code respect the C#/CLR finalization semantics if we want to go with those.


Enlarging the scope of all this, there is already some impending
problems with how destructors are handled in D that can easily create
low-level races. And this applies to struct destructors too, when the
struct is put on the heap or is a member of an object. We're in the need
of a global solution for all this.

<http://d.puremagic.com/issues/show_bug.cgi?id=4621>
<http://d.puremagic.com/issues/show_bug.cgi?id=4624>


More generally, you can't really count on the destructor being called
because the GC is free to decide when to recycle memory. An
implementation that never collects and always allocate new memory is a
perfectly valid GC implementation, even though it might not be very
practical in most cases.

Even such an implementation should free all memory at shutdown, and,
at that point, run finalizers.

Well, not according to the current spec.

No, but a sane implementation made for a sane spec should. ;)


It could make sense to do so, although I'm not sure. Freeing "external"
resources can mean many things: if we're talking about externally
allocated memory, open files, sockets, mutexes, etc., there's no need to
finalize that at the end of the program: the OS will do the cleanup for
us. If we're talking about advisory locks on files, then there's
definitely a need to clear the lock, although I'm not sure it makes
sense to make the release dependent on a non-deterministic GC.

We just need a dispose pattern whereby explicit dispose() instructs the GC to not finalize.


So I'm curious, what resource are we trying to free here?


None. I just came across it in the docs and found it completely insane.

--
Alex Rønne Petersen
a...@lycus.org
http://lycus.org

Reply via email to