Commit b44b83a9 authored by Benjamin Peterson's avatar Benjamin Peterson

Use weakrefs to hold onto classes #2521.

This also causes the _weakref module to be built into the core.
parent 852fa9f0
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
import types import types
from _weakrefset import WeakSet
# Instance of old-style class # Instance of old-style class
class _C: pass class _C: pass
...@@ -95,9 +96,9 @@ class ABCMeta(type): ...@@ -95,9 +96,9 @@ class ABCMeta(type):
abstracts.add(name) abstracts.add(name)
cls.__abstractmethods__ = frozenset(abstracts) cls.__abstractmethods__ = frozenset(abstracts)
# Set up inheritance registry # Set up inheritance registry
cls._abc_registry = set() cls._abc_registry = WeakSet()
cls._abc_cache = set() cls._abc_cache = WeakSet()
cls._abc_negative_cache = set() cls._abc_negative_cache = WeakSet()
cls._abc_negative_cache_version = ABCMeta._abc_invalidation_counter cls._abc_negative_cache_version = ABCMeta._abc_invalidation_counter
return cls return cls
...@@ -128,7 +129,7 @@ class ABCMeta(type): ...@@ -128,7 +129,7 @@ class ABCMeta(type):
"""Override for isinstance(instance, cls).""" """Override for isinstance(instance, cls)."""
# Inline the cache checking when it's simple. # Inline the cache checking when it's simple.
subclass = getattr(instance, '__class__', None) subclass = getattr(instance, '__class__', None)
if subclass in cls._abc_cache: if subclass is not None and subclass in cls._abc_cache:
return True return True
subtype = type(instance) subtype = type(instance)
# Old-style instances # Old-style instances
...@@ -152,7 +153,7 @@ class ABCMeta(type): ...@@ -152,7 +153,7 @@ class ABCMeta(type):
# Check negative cache; may have to invalidate # Check negative cache; may have to invalidate
if cls._abc_negative_cache_version < ABCMeta._abc_invalidation_counter: if cls._abc_negative_cache_version < ABCMeta._abc_invalidation_counter:
# Invalidate the negative cache # Invalidate the negative cache
cls._abc_negative_cache = set() cls._abc_negative_cache = WeakSet()
cls._abc_negative_cache_version = ABCMeta._abc_invalidation_counter cls._abc_negative_cache_version = ABCMeta._abc_invalidation_counter
elif subclass in cls._abc_negative_cache: elif subclass in cls._abc_negative_cache:
return False return False
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
"""Unit tests for abc.py.""" """Unit tests for abc.py."""
import unittest import unittest, weakref
from test import test_support from test import test_support
import abc import abc
...@@ -208,6 +208,22 @@ class TestABC(unittest.TestCase): ...@@ -208,6 +208,22 @@ class TestABC(unittest.TestCase):
C() C()
self.assertEqual(B.counter, 1) self.assertEqual(B.counter, 1)
def test_cache_leak(self):
# See issue #2521.
class A(object):
__metaclass__ = abc.ABCMeta
@abc.abstractmethod
def f(self):
pass
class C(A):
def f(self):
A.f(self)
r = weakref.ref(C)
# Trigger cache.
C().f()
del C
test_support.gc_collect()
self.assertEqual(r(), None)
def test_main(): def test_main():
test_support.run_unittest(TestABC) test_support.run_unittest(TestABC)
......
...@@ -31,6 +31,9 @@ Core and Builtins ...@@ -31,6 +31,9 @@ Core and Builtins
Library Library
------- -------
- Issue #2521: Use weakrefs on for caching in the abc module, so that classes
are not held onto after they are deleted elsewhere.
- Issue #9626: the view methods for collections.OrderedDict() were returning - Issue #9626: the view methods for collections.OrderedDict() were returning
the unordered versions inherited from dict. Those methods are now the unordered versions inherited from dict. Those methods are now
overridden to provide ordered views. overridden to provide ordered views.
...@@ -188,6 +191,9 @@ Library ...@@ -188,6 +191,9 @@ Library
Extension Modules Extension Modules
----------------- -----------------
- As a result of issue #2521, the _weakref module is now compiled into the
interpreter by default.
- Issue #9324: Add parameter validation to signal.signal on Windows in order - Issue #9324: Add parameter validation to signal.signal on Windows in order
to prevent crashes. to prevent crashes.
......
...@@ -118,6 +118,7 @@ pwd pwdmodule.c # this is needed to find out the user's home dir ...@@ -118,6 +118,7 @@ pwd pwdmodule.c # this is needed to find out the user's home dir
# if $HOME is not set # if $HOME is not set
_sre _sre.c # Fredrik Lundh's new regular expressions _sre _sre.c # Fredrik Lundh's new regular expressions
_codecs _codecsmodule.c # access to the builtin codecs and codec registry _codecs _codecsmodule.c # access to the builtin codecs and codec registry
_weakref _weakref.c # weak references
# The zipimport module is always imported at startup. Having it as a # The zipimport module is always imported at startup. Having it as a
# builtin module avoids some bootstrapping problems and reduces overhead. # builtin module avoids some bootstrapping problems and reduces overhead.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment