[Reviewers] [PATCH rfc] rfc: call gc at exit of mercurial

Maciej Fijalkowski fijall at gmail.com
Tue Apr 5 05:31:19 UTC 2016


class A(object):
    def __del__(self):
        print "del"

class B(object):
    pass

b = B()
b.b = b
b.a = A()


This example does not call __del__ in CPython either.

The __del__ is not guaranteed to be called - that's why there is a
painful module finalization procedure where CPython is trying to call
"as much as possible", but there are still no guarantees. If you add
del b; gc.collect() you will see "del" printed. Of course this
involves a cycle, but cycles can come in ways that you don't expect
them and PyPy simply says "everything is GCed". I think it's very much
in line with what python-dev thinks.

On Tue, Apr 5, 2016 at 2:21 AM, Pierre-Yves David
<pierre-yves.david at ens-lyon.org> wrote:
> TL;DR; committer, pypy skip garbage collection at process exit, not call
> __del__ in this case. This seems a divergence from cpython standard. Are we
> okay with that?
>
> More details below.
>
> On 04/03/2016 10:51 AM, Gregory Szorc wrote:
>>
>> On Fri, Apr 1, 2016 at 2:13 AM, Pierre-Yves David
>> <pierre-yves.david at ens-lyon.org <mailto:pierre-yves.david at ens-lyon.org>>
>> wrote:
>>
>>
>>
>>     On 04/01/2016 12:10 AM, Maciej Fijalkowski wrote:
>>
>>         On Fri, Apr 1, 2016 at 9:09 AM, Gregory Szorc
>>         <gregory.szorc at gmail.com <mailto:gregory.szorc at gmail.com>> wrote:
>>
>>
>>
>>                 On Mar 31, 2016, at 23:58, Maciej Fijalkowski
>>                 <fijall at gmail.com <mailto:fijall at gmail.com>> wrote:
>>
>>                 # HG changeset patch
>>                 # User Maciej Fijalkowski <fijall at gmail.com
>>                 <mailto:fijall at gmail.com>>
>>
>>                 # Date 1459493914 -7200
>>                 #      Fri Apr 01 08:58:34 2016 +0200
>>                 # Node ID 66b3737b62635691b5a205dafc80e640880b77ca
>>                 # Parent  9ca7854b963295b8b56d276b903623ac8277f18d
>>                 rfc: call gc at exit of mercurial
>>
>>                 This is not a proper patch, just a visualization of a
>>                 hack I did.
>>                 Locks have a __del__, which test-devel-warnings rely on
>>                 being
>>                 called at the exit of a program. Locks also have
>>                 __exit__ which is
>>                 a more proper way to handle locks, but that test does
>>                 not respect it.
>>                 I would like to know what's the proper way of handling
>>                 this - should
>>                 I fix test, should I just call the GC (which will make
>>                 the command
>>                 line tool slower) or what's the proposed solution
>>
>>
>>             __del__ should be purged and banned from the code base
>>             because it undermines GC and can lead to memory leaks.
>>
>>             For holding on to temporary resources, context managers
>>             (preferred) or try..finally should be used.
>>
>>
>>         So what do we do with lock.__del__ and how tests rely on it?
>>
>>
>>     Can we get details about this test failure and why it relies on it?
>>
>>
>> The existence of lock.__del__ is to catch bugs where people forget to
>> call lock.release. Unfortunately, the presence of __del__ does bad
>> things for garbage collection. So, we want to have a mechanism to detect
>> failure to call lock.release but it can't use __del__. What can we do?
>
>
> It seems like no standard code path rely on this __del__ and it only exist
> as a double safety. Moreover, the __del__ pattern create issue for gc in
> case of cycle and we are quite careful not to create cycle in our low level
> object.
>
> We seems to have 2 code path that trigger this safeguard in tests. On is the
> devel warning on-purpose-clownly code and the second one is an extensions
> enforcing a hard crash to test fncache recovery.
>
>
> About the specific issue here:
>
> Pypy does not automatically garbage object when reference count hit zero. It
> also skip the garbase collecting (and __del__ call) when the programme exit.
> That seems like a divergence from the documented cpython behavior.
>
> As we are not supposed to rely on this behavior, we might consider that
> Mercurial will be fine with this behavior. And in practice the only code
> broken by this lack of __del__ call is one where the code is especially
> wrong on purpose. This test is not testing for the __del__ call or any other
> implicite rollback of the transaction. So we can just call it directly.
>
> If we are fine with pypy not running any __del__ the following patch is
> probably all we want. I've CCed the other committers for opinions.
>
> --- a/tests/test-devel-warnings.t
> +++ b/tests/test-devel-warnings.t
> @@ -9,10 +9,11 @@
>    > command = cmdutil.command(cmdtable)
>    >
>    > @command('buggylocking', [], '')
>    > def buggylocking(ui, repo):
>    >     tr = repo.transaction('buggy')
> +  >     tr.release() # make sure we rollback the transaction as pypy skip
> the __del__
>    >     lo = repo.lock()
>    >     wl = repo.wlock()
>    >     wl.release()
>    >     lo.release()
>    >
>
>
> --
> Pierre-Yves David
>
> _______________________________________________
> Mercurial-devel mailing list
> Mercurial-devel at mercurial-scm.org
> https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel



More information about the Reviewers mailing list