I have the following program written using Island / Oxygene:
uses rtl;
type
TTest = private class
constructor;
begin
writeLn ('constructor TTest');
end;
method DoIt;
begin
writeLn ('TTest.DoIt');
end;
finalizer;
begin
writeLn ('finalizer TTest');
end;
end;
Program = class
private
class method CallTest;
begin
var Test := new TTest;
Test.DoIt;
end;
public
class method Main(args: array of String): Int32;
begin
CallTest;
// gc.GC_gcollect;
end;
end;
end.
The âfinalizerâ only gets called when I implicitly call âgc.GC_gcollectâ before the program terminates. Otherwise, the program just terminates without calling the finalizer. As the finalizerâs main purpose is to clean up when the class gets destroyed I find this behaviour extremely irritating. Furthermore, when I execute the same code in .NET the finalizer gets automatically called before the program terminates.
I am using the Island compiler with Elements v9.3.103.2211.
Neither in .NET nor in Island is the finalizer guaranteed to be called at all. Only when memory is low, or the GC happens to run will it call it. If you need deterministic cleanup you should be using âusingâ/IDisposable.
According to MSDN Finalize the GC will call Finalize on any objects requiring it at shutdown (but not if the process is ungracefully terminated). What cannot be said with any certainty is whether or when the Finalizer might be called before shutdown (or some other conditions under which finalisers can be blocked or otherwise not perform as might be expected).
But based on the .net docs I would still expect a finalizer to be called if a process terminates normally and without any of the complications called out in those docs.
In the following link it says: âFinalizers are also called when the program exitsâ
In Dispose pattern, there should be public Dispose, and a protected virtual Dispose, for the âdisposingâ to work, the Finalizer MUST to kick in at the program exitâŚ
Can we have Finalizer to run at Process exit, on Island? This is critical for my TensorFlow lib to work!
// Protected implementation of Dispose pattern.
protected override void Dispose(bool disposing)
{
if (disposed)
return;
if (disposing) { // This part of code requires Finalizer to
// do the final safe net.
// Free any other managed objects here.
//
}
// Free any unmanaged objects here.
//
disposed = true;
// Call the base class implementation.
base.Dispose(disposing);
}
Finalizer is a âsafety netâ to resort, not to abuse.
But for Dispose pattern, the call to Finalizer is a necessary safety net.
It needs to be called AUTOMATICALLY on Process Exit when destroying the object, if it has NOT been called by GC. The GC itself may or may not call Finalizer, and if it calls, the call will be in-deterministic.
The principle should apply to COM-based memory manager too, that is, Finalizer should be called upon object destroy.
Will âSupressFinalizerâ also be supported to suppress Finalizer?
So COM is different; it uses reference counting and will trigger an IDispose on reaching 0.
I have an issue logged to trigger GC shutdown on process exit, but boehm makes no gaurantees. So atexit is a much better candidate for your usecase.
I am not sure how this can clean up instance-based unmanaged resource (in my case, all native TensorFlow C pointers), none global (unless I manually manage a list of those resources which is clumsy. )
Looks like COM is a better option for my situation?
can you tell me what the exact problem is you are solving? Remember that the GC does work. At which point do you need deterministic cleanup for this? (If so, might the IDisposable pattern be a better option?)
I did implement IDisposable pattern. But I still want Finalizer to get called at Object destroy, as long as Finalizer is defined.
The reason is to have a similar .NET behavior on Island platform, so in case my user FORGET to call Dispose(), there is still an ultimate safety net to prevent resource leaking.
yes thatâs what the GC is for. However the only time it doesnât trigger, is when you shut down the app right away. It is guaranteed to run âeventuallyâ normally. (Note that .NET is the same. It usually does but makes no promises)
@ck
But the OPâs code as in below, doesnât have Finalizer get called?
You mentioned that you logged an issue to run Finalizer at Program Exit, will that garanttee Finalizer will be called at Program Exit? I am confused
uses rtl;
type
TTest = private class
constructor;
begin
writeLn (âconstructor TTestâ);
end;
method DoIt;
begin
writeLn ('TTest.DoIt');
end;
finalizer;
begin
writeLn ('finalizer TTest');
end;
end;
Program = class
private
class method CallTest;
begin
var Test := new TTest;
Test.DoIt;
end;
public
class method Main(args: array of String): Int32;
begin
CallTest;
What I mean is, the GC will call it âeventuallyâ, unless your application shuts down before it gets to it. Iâm forcing a GC now before shutdown which should help in your case. But the best solution is to do implement IDisposable (and let users use that); thereâs a supressfinalize now you can use to ensure it doesnât re-trigger finalize.