Message8898
In dialogue with Jim, I developed a solution based on what was referred to as FinalizeGuardian in http://bugs.jython.org/issue1634167.
Appended is only a draft and not yet an actual fix, because I wanted to discuss some of its implications here first. In addition to the appended stuff one would have to change all the XxxDerived classes as follows:
Let XxxDerived-classes implement FinalizablePyObject
and add a member
FinalizeTrigger finalizeTrigger;
like I demonstrated with PyFinalizableInstance and PyFinalizableObject.
In every constructor must be appended:
PyType self_type=getType();
PyObject impl=self_type.lookup("__del__");
if (impl!=null) finalizeTrigger = FinalizeTrigger.makeTrigger(this);
And finally add a __del__-method:
public void __del__() {
PyObject impl = self_type.lookup("__del__");
if (impl != null) {
impl.__get__(this,self_type).__call__();
FinalizeTrigger.resurrectOnDemand(this);
}
}
IMHO, this should fix it; at least with the same constraint as in the fix of issue 1634167. The nice thing is, that for instances of XxxDerived that don't have a __del__ finalizer, Java won't have to create an expensive Java-finalizer, since finalizeTrigger just stays null.
I developed this approach also with JyNI-integration as a design goal. Especially the methods FinalizeTrigger.prohibitFinalize and FinalizeTrigger.allowFinalize might seem inherently evil as they allow to make certain objects temporarily immortal. To implement a clean garbage collection in JyNI, it sometimes needs to resurrect a gc'ed object in a controlled way and in this case, the finalizer, if any, should not be called by a FinalizeTrigger, nor should the object be reclaimed. JyNI needs this time to check, whether native resources exist that still need the corresponding object.
I reasoned carefully about this and do not see a feasible alternative to this approach. However, I will do my best to let such situations arise as rarely as possible.
Again, if JyNI is not used, this evil stuff won't be done anyway. The implementation just ensures that it can be done without breaking Jython's own finalization process.
As an implication of this, it must be forbidden for subclasses of PyObject to implement finalize(), which I enforce by adding
protected final void finalize() throws Throwable {}
to it. An appropriate adjustment for PyFinalizableInstance is included.
However, it might break existing third-party implemented subclasses of PyObject, if they implement finalize. I still recommend this change for Jython 2.7., as such third-party implementations would be trivial to fix. Additionally, I suppose that they are rather rare, if existent at all, since there is a common consens to avoid using finalizers.
Another note: The attached implementation would allow to reproduce CPython's behavior regarding to repeated object resurrection. Prior to 3.4 it would also repeatedly call the finalizer, which is not emulated by current solution for http://bugs.jython.org/issue1634167. My proposed solution would fix this for http://bugs.jython.org/issue1634167 as well.
However, Jim pointed out that it might be better to directly stick to Cpython's >= 3.4 behavior (i.e. call __del__ only once, like Java would do and thus prohibit repeated resurrection). The proposed solution would support both variants and switching between them is a trivial adjustment. One could even make it configurable.
I did not yet test this approach with Jython, but I tested the used principles with some dummy classes in detail. Depending on your reply I will do actual test with Jython and work it out as an actual patch. |
|
Date |
User |
Action |
Args |
2014-07-30 16:59:27 | stefan.richthofer | set | messageid: <1406739567.25.0.476550088587.issue1057@psf.upfronthosting.co.za> |
2014-07-30 16:59:27 | stefan.richthofer | set | recipients:
+ stefan.richthofer, fwierzbicki, pjenvey, zyasoft, ajdavis |
2014-07-30 16:59:27 | stefan.richthofer | link | issue1057 messages |
2014-07-30 16:59:26 | stefan.richthofer | create | |
|