Carl Friedrich Bolz  committed 7bddec1

properly do the fix: need two sets, one for walking, one for counting. need to deal with dict proxies

  • Participants
  • Parent commits f6aea34

Comments (0)

Files changed (1)

File libbench/

         return result
+dict_proxy = type(OSHeapSize.__dict__)
 class BaseHeapCollector(object):
     """ Basic heap collector that implements all methods for walking objects,
     def __init__(self):
         self.seen = set()
+        self.counted = set()
         self.deferred_dicts = []
         self.typecategory = {
             self.get_key(1): "numeric",
             self.get_key(""): "text",
             self.get_key(u""): "text",
-        self.seen.add(id(self))
-        self.seen.add(id(self.seen))
-        self.seen.add(id(self.deferred_dicts))
-        self.seen.add(id(self.typecategory))
+        for obj in [self, self.seen, self.counted, self.deferred_dicts, self.typecategory]:
+            self.seen.add(id(obj))
+            self.counted.add(id(obj))
     def _count_obj(self, obj):
         """ Count the size of the given object including its dictionary"""
         obj_id = id(obj)
         # skip if we've already seen this object
-        if obj_id in self.seen:
+        if obj_id in self.counted:
-        # if object is a dict, do it later, because XXX
+        # if object is a dict, do it later, because it could be an object's
+        # dict
         if isinstance(obj, dict) and self.deferred_dicts is not None:
-        self.seen.add(obj_id) # mark object as seen
+        self.counted.add(obj_id) # mark object as seen
         # remeber all types we have seen
         key = self.get_key(obj)
         # add object to total memory usage (for that type)
         self.count_obj(obj, key)
-        # if object has a dict that we haven't mesaured yet, do it now
+        # if object has a dict that we haven't measured yet, do it now
         d = get_real_dict(obj)
-        if d is None or id(d) in self.seen:
-            return
+        dicts = [d]
+        if isinstance(d, dict_proxy):
+            dicts.append(gc.get_referents(d)[0])
+        for d in dicts:
+            if d is None or id(d) in self.counted:
+                return
         self.count_dict(obj, d, key)
-        self.seen.add(id(d))
+        self.counted.add(id(d))
     def walk_obj(self, obj):
         """ Follow all referents of the given object and add them to the
         total memory size of its type category """
-        #if id(obj) in self.seen or obj in self.deferred_dicts:
-        #    return
+        obj_id = id(obj)
+        if obj_id in self.seen:
+            return
+        self.seen.add(obj_id)
         referents = gc.get_referents(obj)
         for ref in referents:
-            self._count_obj(ref)
+            self.walk_obj(ref)
     def finish(self):
         """ Count all dictionaries that were skipped in _count_obj """