[openstack-dev] [all] i need some help on this bug Bug #1365892
Mike Bayer
mbayer at redhat.com
Wed Sep 10 17:04:02 UTC 2014
On Sep 10, 2014, at 4:11 AM, Li Tianqing <jazeltq at 163.com> wrote:
> After some research, i find the reason for the cycle reference. In closure, the _fix_paswords.func_closre reference the _fix_passwords. So the
> cycle reference happened.
> And in https://thp.io/2012/python-gc/python_gc_final_2012-01-22.pdf page 5, it says that
> We observe that Python implementations with distinct GCs behave differently: CPython does not even try to get the order of finalizers right, and
> simply puts uncollectable objects into the global list of garbage for the developer to deal with manually.
> So the gc can not handle cycle reference, then the memory leak happened.
An object is only uncollectable in Python if it has a __del__ method and is part of an unreachable cycle. Based on a grep, there is only one class in oslo.messaging that has a __del__ and that is ConnectionContext in _drivers/amqp.py.
Removing the __del__ method from this object would be the best approach. There’s nothing wrong with reference cycles in Python as long as we don’t use __del__, which IMHO has no legitimate use case. Additionally, it is very difficult to be 100% vigilant against reference cycles reappearing in many cases, but it is extremely simple to be 100% vigilant about disallowing __del__.
In this case it appears to be a “safety” in case someone uses the ConnectionContext object outside of being a context manager. I’d fix that and require that it be used as a context manager only. Guessing that the user is going to mis-use an object and provide __del__ to protect the user is a bad idea - and if you genuinely need this pattern, you use a weakref callback instead:
import weakref
class MyCleanupThing(object):
def __init__(self):
self.connection = connection = "Some Connection"
self._ref = weakref.ref(
# key: the weakref callback *cannot* refer to self
self, lambda ref: MyCleanupThing._cleanup(connection))
@staticmethod
def _cleanup(connection):
print("Cleaning up %s!" % connection)
mc = MyCleanupThing()
print("about to clean up...")
del mc
print("should be clean!")
output:
about to clean up...
Cleaning up Some Connection!
should be clean!
>
> If there is something wrong, please fix it. Thanks
>
> --
> Best
> Li Tianqing
>
> 在 2014-09-10 11:52:28,"Li Tianqing" <jazeltq at 163.com> 写道:
> Hello,
> I use backdoor of eventlet to enable gc.DEBUG_LEAK, and after wait a few minutes, i can sure that there will some objects that can not be collected by gc.collect in gc.garbage.
> Those looks like this (catched in ceilometer-collector)
>
> ['_context_auth_token', 'auth_token', 'new_pass'],
> (<cell at 0x363bc58: list object at 0x361c170>,
> <cell at 0x363bda8: function object at 0x361a5f0>),
> <function _fix_passwords at 0x361a5f0>,
> <cell at 0x363bde0: list object at 0x363c680>,
> <cell at 0x363bd70: function object at 0x361a668>,
> ['_context_auth_token', 'auth_token', 'new_pass'],
> (<cell at 0x363bde0: list object at 0x363c680>,
> <cell at 0x363bd70: function object at 0x361a668>),
> <function _fix_passwords at 0x361a668>,
> <cell at 0x363bf30: list object at 0x361b680>,
> <cell at 0x363e168: function object at 0x361a758>,
> ['_context_auth_token', 'auth_token', 'new_pass'],
> (<cell at 0x363bf30: list object at 0x361b680>,
> <cell at 0x363e168: function object at 0x361a758>),
> <function _fix_passwords at 0x361a758>,
> <cell at 0x363e1a0: list object at 0x363cdd0>,
> <cell at 0x363e130: function object at 0x361a7d0>,
>
> and i suspect those code in oslo.messaging
>
> def _safe_log(log_func, msg, msg_data):
> """Sanitizes the msg_data field before logging."""
> SANITIZE = ['_context_auth_token', 'auth_token', 'new_pass']
>
> def _fix_passwords(d):
> """Sanitizes the password fields in the dictionary."""
> for k in d.iterkeys():
> if k.lower().find('password') != -1:
> d[k] = '<SANITIZED>'
> elif k.lower() in SANITIZE:
> d[k] = '<SANITIZED>'
> elif isinstance(d[k], dict):
> _fix_passwords(d[k])
> return d
>
> return log_func(msg, _fix_passwords(copy.deepcopy(msg_data)))
>
> i can resolve this problem by add _fix_passwords = None before _safe_log returns.
>
> But i do not really understand why this problem happened, and in depth why the gc can not collect those object. Although i can make those uncollectable objects disappeared.
> But this is not good enough, because if you do not understand it you will write out some code like this in future, and then also has memory leak too.
>
> So can some one helps me give some detailed on recursive closure used like the code above, and on why gc can not collect them.
> Thanks a lot lot ......
>
> --
> Best
> Li Tianqing
>
>
>
>
> _______________________________________________
> OpenStack-dev mailing list
> OpenStack-dev at lists.openstack.org
> http://lists.openstack.org/cgi-bin/mailman/listinfo/openstack-dev
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.openstack.org/pipermail/openstack-dev/attachments/20140910/a6e58056/attachment.html>
More information about the OpenStack-dev
mailing list