summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJason Madden <jamadden@gmail.com>2020-01-23 11:38:41 -0600
committerJason Madden <jamadden@gmail.com>2020-01-23 11:38:41 -0600
commit72dc05b90fb26385f0ad100376e0875439825da8 (patch)
tree6e8a8ddb202f76cb1dad8b90a1ee077a5f0bf752
parentcacd85b78d530336136cac40c42019b8b6946eb0 (diff)
downloadzope-interface-slots.tar.gz
Avoid allocating space for tagged values unless they're used. This saves another few percent.slots
-rw-r--r--CHANGES.rst10
-rw-r--r--src/zope/interface/interface.py12
2 files changed, 19 insertions, 3 deletions
diff --git a/CHANGES.rst b/CHANGES.rst
index c5de832..b976ba1 100644
--- a/CHANGES.rst
+++ b/CHANGES.rst
@@ -17,6 +17,16 @@
an undocumented private C API function, and helps make some
instances require less memory. See `PR 154 <https://github.com/zopefoundation/zope.interface/pull/154>`_.
+- Reduce memory usage in other ways based on observations of usage
+ patterns in Zope (3) and Plone code bases.
+
+ - Specifications with no dependents are common (more than 50%) so
+ avoid allocating a ``WeakKeyDictionary`` unless we need it.
+ - Likewise, tagged values are relatively rare, so don't allocate a
+ dictionary to hold them until they are used.
+
+ The changes in this release resulted in a 7% memory reduction after
+ loading about 6,000 modules that define about 2,200 interfaces.
4.7.1 (2019-11-11)
==================
diff --git a/src/zope/interface/interface.py b/src/zope/interface/interface.py
index c374cef..f501077 100644
--- a/src/zope/interface/interface.py
+++ b/src/zope/interface/interface.py
@@ -67,7 +67,9 @@ class Element(object):
self.__name__ = __name__
self.__doc__ = __doc__
- self.__tagged_values = {}
+ # Tagged values are rare, especially on methods or attributes.
+ # Deferring the allocation can save substantial memory.
+ self.__tagged_values = None
def getName(self):
""" Returns the name of the object. """
@@ -79,18 +81,22 @@ class Element(object):
def getTaggedValue(self, tag):
""" Returns the value associated with 'tag'. """
+ if not self.__tagged_values:
+ raise KeyError(tag)
return self.__tagged_values[tag]
def queryTaggedValue(self, tag, default=None):
""" Returns the value associated with 'tag'. """
- return self.__tagged_values.get(tag, default)
+ return self.__tagged_values.get(tag, default) if self.__tagged_values else default
def getTaggedValueTags(self):
""" Returns a list of all tags. """
- return self.__tagged_values.keys()
+ return self.__tagged_values.keys() if self.__tagged_values else ()
def setTaggedValue(self, tag, value):
""" Associates 'value' with 'key'. """
+ if self.__tagged_values is None:
+ self.__tagged_values = {}
self.__tagged_values[tag] = value