| Thread overview | ||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
May 03, 2009 Destructors and Deterministic Memory Management | ||||
|---|---|---|---|---|
| ||||
Two closely related topics here: 1. It is often nice to be able to create a single object that works with both GC and deterministic memory management. The idea is that, if delete is called manually, all sub-objects would be freed deterministically, but the object could still safely be GC'd. Since the destructor called by the GC can't reference sub-objects, would it be feasible to have two destructors for each class, one that is called when delete is invoked manually and another that is called by the GC? 2. One possible solution is to allocate the sub-objects whose lifetimes can't exceed that of the main object on the C heap, and put std.c.stdlib.free() calls in the destructor. However, according to the spec, the GC is not guaranteed to call the destructor for all unreferenced objects. Under what circumstances would the d'tor not get called, leading to a memory leak if this strategy was used? | ||||
May 03, 2009 Re: Destructors and Deterministic Memory Management | ||||
|---|---|---|---|---|
| ||||
Posted in reply to dsimcha | dsimcha wrote:
> Two closely related topics here:
>
> 1. It is often nice to be able to create a single object that works with both
> GC and deterministic memory management. The idea is that, if delete is called
> manually, all sub-objects would be freed deterministically, but the object
> could still safely be GC'd. Since the destructor called by the GC can't
> reference sub-objects, would it be feasible to have two destructors for each
> class, one that is called when delete is invoked manually and another that is
> called by the GC?
This one you already can do. Just write a myDestructor() that does whatever you need, and then call it when necessary.
| |||
May 03, 2009 Re: Destructors and Deterministic Memory Management | ||||
|---|---|---|---|---|
| ||||
Posted in reply to Georg Wrede |
Georg Wrede wrote:
> dsimcha wrote:
>> Two closely related topics here:
>>
>> 1. It is often nice to be able to create a single object that works
>> with both
>> GC and deterministic memory management. The idea is that, if delete
>> is called
>> manually, all sub-objects would be freed deterministically, but the
>> object
>> could still safely be GC'd. Since the destructor called by the GC can't
>> reference sub-objects, would it be feasible to have two destructors
>> for each
>> class, one that is called when delete is invoked manually and another
>> that is
>> called by the GC?
>
> This one you already can do. Just write a myDestructor() that does whatever you need, and then call it when necessary.
Actually, a pattern I stole from C# was dispose. I have a module lying around somewhere that defines a Disposable interface with a void dispose(); method. There's also a mixin that implements much of the logic and boilerplate for you.
It also defines void dispose(T)(T) and void destroy(T)(ref T); destroy
works like delete except that it will call dispose on the passed value
if it can find it. Then I just use destroy everywhere instead of
delete, unless it's for a scoped instance in which case I use dispose.
-- Daniel
| |||
May 05, 2009 Re: Destructors and Deterministic Memory Management | ||||
|---|---|---|---|---|
| ||||
Posted in reply to dsimcha | dsimcha wrote:
> Two closely related topics here:
>
> 1. It is often nice to be able to create a single object that works with both
> GC and deterministic memory management. The idea is that, if delete is called
> manually, all sub-objects would be freed deterministically, but the object
> could still safely be GC'd. Since the destructor called by the GC can't
> reference sub-objects, would it be feasible to have two destructors for each
> class, one that is called when delete is invoked manually and another that is
> called by the GC?
You can do this today with both Druntime on D 2.0 and Tango on D 1.0, though it isn't the most performant approach. The code would look something like this:
import core.runtime;
interface Disposable
{
void dispose();
}
bool handler( Object o )
{
auto d = cast(Disposable) o;
if( d !is null )
{
d.dispose();
return false;
}
return true;
}
static this()
{
Runtime.collectHandler = &handler;
}
If you return false from your collectHandler then the runtime won't call the object's dtor.
| |||
May 05, 2009 Re: Destructors and Deterministic Memory Management | ||||
|---|---|---|---|---|
| ||||
Posted in reply to Sean Kelly |
Sean Kelly wrote:
> ...
>
> import core.runtime;
>
> interface Disposable
> {
> void dispose();
> }
>
> bool handler( Object o )
> {
> auto d = cast(Disposable) o;
>
> if( d !is null )
> {
> d.dispose();
> return false;
> }
> return true;
> }
>
> static this()
> {
> Runtime.collectHandler = &handler;
> }
>
> If you return false from your collectHandler then the runtime won't call the object's dtor.
:O
?cookie SeanK
-- Daniel
| |||
May 05, 2009 Re: Destructors and Deterministic Memory Management | ||||
|---|---|---|---|---|
| ||||
Posted in reply to Sean Kelly | Sean Kelly wrote: > dsimcha wrote: >> Two closely related topics here: >> >> 1. It is often nice to be able to create a single object that works with both >> GC and deterministic memory management. The idea is that, if delete is called >> manually, all sub-objects would be freed deterministically, but the object >> could still safely be GC'd. Since the destructor called by the GC can't >> reference sub-objects, would it be feasible to have two destructors for each >> class, one that is called when delete is invoked manually and another that is >> called by the GC? > > You can do this today with both Druntime on D 2.0 and Tango on D 1.0, though it isn't the most performant approach. The code would look something like this: > > import core.runtime; > > interface Disposable > { > void dispose(); > } > > bool handler( Object o ) > { > auto d = cast(Disposable) o; > > if( d !is null ) > { > d.dispose(); > return false; > } > return true; > } > > static this() > { > Runtime.collectHandler = &handler; > } > > If you return false from your collectHandler then the runtime won't call the object's dtor. I raised this enhancement request, below : http://d.puremagic.com/issues/show_bug.cgi?id=2757 Would this sample code solve these resource management / deterministic memory management issues ? | |||
May 05, 2009 Re: Destructors and Deterministic Memory Management | ||||
|---|---|---|---|---|
| ||||
Posted in reply to Sean Kelly | Sean Kelly wrote:
> dsimcha wrote:
>> Two closely related topics here:
>>
>> 1. It is often nice to be able to create a single object that works with both
>> GC and deterministic memory management. The idea is that, if delete is called
>> manually, all sub-objects would be freed deterministically, but the object
>> could still safely be GC'd. Since the destructor called by the GC can't
>> reference sub-objects, would it be feasible to have two destructors for each
>> class, one that is called when delete is invoked manually and another that is
>> called by the GC?
>
> You can do this today with both Druntime on D 2.0 and Tango on D 1.0, though it isn't the most performant approach. The code would look something like this:
>
> import core.runtime;
>
> interface Disposable
> {
> void dispose();
> }
>
> bool handler( Object o )
> {
> auto d = cast(Disposable) o;
>
> if( d !is null )
> {
> d.dispose();
> return false;
> }
> return true;
> }
>
> static this()
> {
> Runtime.collectHandler = &handler;
> }
>
> If you return false from your collectHandler then the runtime won't call the object's dtor.
Err, if one has an object that needs deterministic destruction, then one calls it (with say myDelete()) to have it release its resources. Until then, of course, it shouldn't get collected. But in any case it won't, because we obviously have a handler to it because we still haven't decided to destruct it. So I assume there's something I don't understand here.
After we're done with destructing (as in having called myDelete()), then we "delete the object", or let it go out of scope. Then it becomes eligible for disposal. So, what's the relevance of Disposable here?
| |||
May 05, 2009 Re: Destructors and Deterministic Memory Management | ||||
|---|---|---|---|---|
| ||||
Posted in reply to Georg Wrede | Georg Wrede wrote: > Sean Kelly wrote: >> dsimcha wrote: >>> Two closely related topics here: >>> >>> 1. It is often nice to be able to create a single object that works with both >>> GC and deterministic memory management. The idea is that, if delete is called >>> manually, all sub-objects would be freed deterministically, but the object >>> could still safely be GC'd. Since the destructor called by the GC can't >>> reference sub-objects, would it be feasible to have two destructors for each >>> class, one that is called when delete is invoked manually and another that is >>> called by the GC? >> >> You can do this today with both Druntime on D 2.0 and Tango on D 1.0, though it isn't the most performant approach. The code would look something like this: >> >> import core.runtime; >> >> interface Disposable >> { >> void dispose(); >> } >> >> bool handler( Object o ) >> { >> auto d = cast(Disposable) o; >> >> if( d !is null ) >> { >> d.dispose(); >> return false; >> } >> return true; >> } >> >> static this() >> { >> Runtime.collectHandler = &handler; >> } >> >> If you return false from your collectHandler then the runtime won't call the object's dtor. > > Err, if one has an object that needs deterministic destruction, then one calls it (with say myDelete()) to have it release its resources. Until then, of course, it shouldn't get collected. But in any case it won't, because we obviously have a handler to it because we still haven't decided to destruct it. So I assume there's something I don't understand here. s/handler/reference/ > After we're done with destructing (as in having called myDelete()), then we "delete the object", or let it go out of scope. Then it becomes eligible for disposal. So, what's the relevance of Disposable here? > | |||
May 06, 2009 Re: Destructors and Deterministic Memory Management | ||||
|---|---|---|---|---|
| ||||
Posted in reply to Georg Wrede | Georg Wrede wrote:
> Sean Kelly wrote:
>> dsimcha wrote:
>>> Two closely related topics here:
>>>
>>> 1. It is often nice to be able to create a single object that works with both
>>> GC and deterministic memory management. The idea is that, if delete is called
>>> manually, all sub-objects would be freed deterministically, but the object
>>> could still safely be GC'd. Since the destructor called by the GC can't
>>> reference sub-objects, would it be feasible to have two destructors for each
>>> class, one that is called when delete is invoked manually and another that is
>>> called by the GC?
>>
>> You can do this today with both Druntime on D 2.0 and Tango on D 1.0, though it isn't the most performant approach. The code would look something like this:
>>
>> import core.runtime;
>>
>> interface Disposable
>> {
>> void dispose();
>> }
>>
>> bool handler( Object o )
>> {
>> auto d = cast(Disposable) o;
>>
>> if( d !is null )
>> {
>> d.dispose();
>> return false;
>> }
>> return true;
>> }
>>
>> static this()
>> {
>> Runtime.collectHandler = &handler;
>> }
>>
>> If you return false from your collectHandler then the runtime won't call the object's dtor.
>
> Err, if one has an object that needs deterministic destruction, then one calls it (with say myDelete()) to have it release its resources. Until then, of course, it shouldn't get collected. But in any case it won't, because we obviously have a handler to it because we still haven't decided to destruct it. So I assume there's something I don't understand here.
>
> After we're done with destructing (as in having called myDelete()), then we "delete the object", or let it go out of scope. Then it becomes eligible for disposal. So, what's the relevance of Disposable here?
The collectHandler will only be called if an object is collected by the GC, not if it's explicitly deleted. So you could write the dtor in a way that assumes all referenced subobjects are still valid and use dispose for cleanup of garbage collected instances only. To me that sounded fairly close to what dsimcha was asking for.
| |||
May 06, 2009 Re: Destructors and Deterministic Memory Management | ||||
|---|---|---|---|---|
| ||||
Posted in reply to Sean Kelly | Sean Kelly wrote: > Georg Wrede wrote: >> Sean Kelly wrote: >>> dsimcha wrote: >>>> >>>> 1. It is often nice to be able to create a single object that >>>> works with both GC and deterministic memory management. The >>>> idea is that, if delete is called manually, all sub-objects >>>> would be freed deterministically, but the object could still >>>> safely be GC'd. Since the destructor called by the GC can't reference sub-objects, would it be feasible to have two >>>> destructors for each class, one that is called when delete is >>>> invoked manually and another that is called by the GC? >>> You can do this today with both Druntime on D 2.0 and Tango on D 1.0, though it isn't the most performant approach. The code would look something like this: >>> >>> import core.runtime; >>> >>> interface Disposable >>> { >>> void dispose(); >>> } >>> >>> bool handler( Object o ) >>> { >>> auto d = cast(Disposable) o; >>> >>> if( d !is null ) >>> { >>> d.dispose(); >>> return false; >>> } >>> return true; >>> } >>> >>> static this() >>> { >>> Runtime.collectHandler = &handler; >>> } >>> >>> If you return false from your collectHandler then the runtime won't call the object's dtor. >> >> Err, if one has an object that needs deterministic destruction, then one calls it (with say myDelete()) to have it release its resources. Until then, of course, it shouldn't get collected. But in any case it won't, because we obviously have a handler to it because we still haven't decided to destruct it. So I assume there's something I don't understand here. >> >> After we're done with destructing (as in having called myDelete()), then we "delete the object", or let it go out of scope. Then it becomes eligible for disposal. So, what's the relevance of Disposable here? > > The collectHandler will only be called if an object is collected by the GC, not if it's explicitly deleted. So you could write the dtor in a way that assumes all referenced subobjects are still valid and use dispose for cleanup of garbage collected instances only. To me that sounded fairly close to what dsimcha was asking for. Dsimcha wrote "Since the destructor called by the GC can't reference sub-objects", I got into thinking that we'd then need a myDestructor. But delete myobject; calls ~this() in myobject, as does the GC, as does program exit. I also tested, and the referenced other objects did get deleted. No problem. That implies releasing other resources works, by simply having such release code in ~this() for the object. I found no difference in calling delete or letting the GC do it. So, originally dsimcha's problem was imagined? | |||
Copyright © 1999-2021 by the D Language Foundation
Permalink
Reply