Author: Armin Rigo <ar...@tunes.org> Branch: Changeset: r92380:90a0d3659179 Date: 2017-09-14 00:32 +0200 http://bitbucket.org/pypy/pypy/changeset/90a0d3659179/
Log: Found out that gc.get_objects() returns some, but not all, objects with finalizers, in some strange way. More precisely, it completely misses objects with finalizers that have recently become unreachable, but it no longer misses these objects after the next major collection occurred. diff --git a/rpython/memory/gc/base.py b/rpython/memory/gc/base.py --- a/rpython/memory/gc/base.py +++ b/rpython/memory/gc/base.py @@ -336,6 +336,7 @@ callback2, attrname = _convert_callback_formats(callback) # :-/ setattr(self, attrname, arg) self.root_walker.walk_roots(callback2, callback2, callback2) + self.enum_live_with_finalizers(callback, arg) self.enum_pending_finalizers(callback, arg) enumerate_all_roots._annspecialcase_ = 'specialize:arg(1)' @@ -348,6 +349,12 @@ i += 1 enum_pending_finalizers._annspecialcase_ = 'specialize:arg(1)' + def enum_live_with_finalizers(self, callback, arg): + # as far as possible, enumerates the live objects with finalizers, + # even if they have not been detected as unreachable yet (but may be) + pass + enum_live_with_finalizers._annspecialcase_ = 'specialize:arg(1)' + def _copy_pending_finalizers_deque(self, deque, copy_fn): tmp = self.AddressDeque() while deque.non_empty(): diff --git a/rpython/memory/gc/incminimark.py b/rpython/memory/gc/incminimark.py --- a/rpython/memory/gc/incminimark.py +++ b/rpython/memory/gc/incminimark.py @@ -2515,6 +2515,11 @@ MovingGCBase.enumerate_all_roots(self, callback, arg) enumerate_all_roots._annspecialcase_ = 'specialize:arg(1)' + def enum_live_with_finalizers(self, callback, arg): + self.probably_young_objects_with_finalizers.foreach(callback, arg, 2) + self.old_objects_with_finalizers.foreach(callback, arg, 2) + enum_live_with_finalizers._annspecialcase_ = 'specialize:arg(1)' + def _collect_obj(self, obj, ignored): # Ignore pinned objects, which are the ones still in the nursery here. # Cache effects: don't read any flag out of 'obj' at this point. diff --git a/rpython/memory/gc/minimark.py b/rpython/memory/gc/minimark.py --- a/rpython/memory/gc/minimark.py +++ b/rpython/memory/gc/minimark.py @@ -1780,6 +1780,11 @@ MovingGCBase.enumerate_all_roots(self, callback, arg) enumerate_all_roots._annspecialcase_ = 'specialize:arg(1)' + def enum_live_with_finalizers(self, callback, arg): + self.probably_young_objects_with_finalizers.foreach(callback, arg, 2) + self.old_objects_with_finalizers.foreach(callback, arg, 2) + enum_live_with_finalizers._annspecialcase_ = 'specialize:arg(1)' + @staticmethod def _collect_obj(obj, objects_to_trace): objects_to_trace.append(obj) diff --git a/rpython/memory/support.py b/rpython/memory/support.py --- a/rpython/memory/support.py +++ b/rpython/memory/support.py @@ -269,22 +269,23 @@ self.index_in_oldest = index + 1 return result - def foreach(self, callback, arg): + def foreach(self, callback, arg, step=1): """Invoke 'callback(address, arg)' for all addresses in the deque. Typically, 'callback' is a bound method and 'arg' can be None. + If step > 1, only calls it for addresses multiple of 'step'. """ chunk = self.oldest_chunk index = self.index_in_oldest while chunk is not self.newest_chunk: while index < chunk_size: callback(chunk.items[index], arg) - index += 1 + index += step chunk = chunk.next - index = 0 + index -= chunk_size limit = self.index_in_newest while index < limit: callback(chunk.items[index], arg) - index += 1 + index += step foreach._annspecialcase_ = 'specialize:arg(1)' def delete(self): diff --git a/rpython/memory/test/test_support.py b/rpython/memory/test/test_support.py --- a/rpython/memory/test/test_support.py +++ b/rpython/memory/test/test_support.py @@ -160,6 +160,10 @@ ll.foreach(callback, 42) assert seen == addrs + seen = [] + ll.foreach(callback, 42, step=2) + assert seen == addrs[::2] + for a in addrs: b = ll.popleft() assert a == b _______________________________________________ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit