Rev 142: Instead of using weakrefs, put the proxy ref as part of the _MemObject in http://bazaar.launchpad.net/~jameinel/meliae/mem-object-collection

John Arbash Meinel john at arbash-meinel.com
Mon Dec 28 20:08:10 GMT 2009


At http://bazaar.launchpad.net/~jameinel/meliae/mem-object-collection

------------------------------------------------------------
revno: 142
revision-id: john at arbash-meinel.com-20091228200751-9dx6lqgwvyn13tv5
parent: john at arbash-meinel.com-20091228195848-y0ici6c6l4humkdp
committer: John Arbash Meinel <john at arbash-meinel.com>
branch nick: mem-object-collection
timestamp: Mon 2009-12-28 14:07:51 -0600
message:
  Instead of using weakrefs, put the proxy ref as part of the _MemObject
  
  This saves a bunch of memory in an extra dict + all the weakref instances.
  It adds one pointer per _MemObject, but we have quite a few code paths
  that end up creating all proxies anyway.
-------------- next part --------------
=== modified file 'meliae/_loader.pyx'
--- a/meliae/_loader.pyx	2009-12-28 19:58:48 +0000
+++ b/meliae/_loader.pyx	2009-12-28 20:07:51 +0000
@@ -37,8 +37,6 @@
     # void fprintf(void *, char *, ...)
     # void *stderr
 
-import weakref
-
 
 ctypedef struct RefList:
     long size
@@ -147,6 +145,7 @@
     PyObject *name
     RefList *referrer_list
     unsigned long total_size
+    PyObject *proxy
 
 
 cdef int _free_mem_object(_MemObject *cur) except -1:
@@ -168,6 +167,8 @@
     cur.name = NULL
     _free_ref_list(cur.referrer_list)
     cur.referrer_list = NULL
+    Py_XDECREF(cur.proxy)
+    cur.proxy = NULL
     PyMem_Free(cur)
     return 1
 
@@ -194,7 +195,6 @@
     cdef _MemObject *_obj
     # If not NULL, this will be freed when this object is deallocated
     cdef _MemObject *_managed_obj
-    cdef object __weakref__
 
     def __init__(self, collection):
         self.collection = collection
@@ -324,13 +324,11 @@
     cdef readonly int _active      # How many slots have real data
     cdef readonly int _filled      # How many slots have real or dummy
     cdef _MemObject** _table       # _MemObjects are stored inline
-    cdef public object _proxies    # _MemObjectProxy instances
 
     def __init__(self):
         self._table_mask = 1024 - 1
         self._table = <_MemObject**>PyMem_Malloc(sizeof(_MemObject*)*1024)
         memset(self._table, 0, sizeof(_MemObject*)*1024)
-        self._proxies = weakref.WeakValueDictionary()
 
     def __len__(self):
         return self._active
@@ -394,12 +392,13 @@
     cdef _MemObjectProxy _proxy_for(self, address, _MemObject *val):
         cdef _MemObjectProxy proxy
 
-        if address in self._proxies:
-            proxy = self._proxies[address]
-        else:
+        if val.proxy == NULL:
             proxy = _MemObjectProxy(self)
             proxy._obj = val
-            self._proxies[address] = proxy
+            val.proxy = <PyObject *>proxy
+            Py_INCREF(val.proxy)
+        else:
+            proxy = <object>val.proxy
         return proxy
 
     def __getitem__(self, at):
@@ -418,6 +417,8 @@
             raise KeyError('address %s not present' % (at,))
         if proxy is None:
             proxy = self._proxy_for(address, slot[0])
+        else:
+            assert proxy._obj == slot[0]
         return proxy
 
     def get(self, at, default=None):
@@ -438,11 +439,16 @@
         slot = self._lookup(address)
         if slot[0] == NULL or slot[0] == _dummy:
             raise KeyError('address %s not present' % (at,))
-        proxy = self._proxies.get(address, None)
-        if proxy is not None:
-            # Have the proxy take over the memory lifetime
+        if slot[0].proxy != NULL:
+            # Have the proxy take over the memory lifetime. At the same time,
+            # we break the reference cycle, so that the proxy will get cleaned
+            # up properly
+            proxy = <object>slot[0].proxy
             proxy._managed_obj = proxy._obj
+            Py_DECREF(slot[0].proxy)
+            slot[0].proxy = NULL
         else:
+            # Without a proxy, we just nuke the object
             self._clear_slot(slot)
         slot[0] = _dummy
         self._active -= 1
@@ -571,9 +577,7 @@
         if self._filled * 3 > (self._table_mask + 1) * 2:
             # We need to grow
             self._resize(self._active * 2)
-        proxy = _MemObjectProxy(self)
-        proxy._obj = new_entry
-        self._proxies[address] = proxy
+        proxy = self._proxy_for(address, new_entry)
         return proxy
 
     def __dealloc__(self):
@@ -605,10 +609,10 @@
                 values.append(address)
         return values
 
+    def iteritems(self):
+        return self.items()
+
     def items(self):
-        return self.iteritems()
-
-    def iteritems(self):
         """Iterate over (key, value) tuples."""
         cdef long i
         cdef _MemObject *cur
@@ -627,6 +631,9 @@
 
     def itervalues(self):
         """Return an iterable of values stored in this map."""
+        return self.values()
+
+    def values(self):
         # This returns a list, but that is 'close enough' for what we need
         cdef long i
         cdef _MemObject *cur



More information about the bazaar-commits mailing list