diff --git a/Src/IronPython/Runtime/Types/PythonType.cs b/Src/IronPython/Runtime/Types/PythonType.cs index e3989f5dc..984833923 100644 --- a/Src/IronPython/Runtime/Types/PythonType.cs +++ b/Src/IronPython/Runtime/Types/PythonType.cs @@ -39,7 +39,7 @@ public partial class PythonType : IPythonMembersList, IDynamicMetaObjectProvider private PythonTypeAttributes _attrs; // attributes of the type private int _flags; // CPython-like flags on the type private int _version = GetNextVersion(); // version of the type - private List _subtypes; // all of the subtypes of the PythonType + private List> _subtypes; // all of the subtypes of the PythonType private PythonContext _pythonContext; // the context the type was created from, or null for system types. private bool? _objectNew, _objectInit; // true if the type doesn't override __new__ / __init__ from object. internal Dictionary _cachedGets; // cached gets on user defined type instances @@ -76,7 +76,6 @@ public partial class PythonType : IPythonMembersList, IDynamicMetaObjectProvider [MultiRuntimeAware] private static int MasterVersion = 1; private static readonly CommonDictionaryStorage _pythonTypes = new CommonDictionaryStorage(); - private static readonly WeakReference[] _emptyWeakRef = Array.Empty(); private static readonly object _subtypesLock = new object(); internal static readonly Func DefaultMakeException = (message, innerException) => new Exception(message, innerException); internal static readonly Func DefaultMakeExceptionNoInnerException = (message) => new Exception(message); @@ -680,17 +679,15 @@ public static PythonDictionary __prepare__([ParamDictionary]IDictionary subtypes = SubTypes; + var subtypes = SubTypes; if (subtypes != null) { PythonContext pc = context.LanguageContext; - foreach (WeakReference wr in subtypes) { - if (wr.IsAlive) { - PythonType pt = (PythonType)wr.Target; - + foreach (var wr in subtypes) { + if (wr.TryGetTarget(out PythonType pt)) { if (pt.PythonContext == null || pt.PythonContext == pc) { - ret.AddNoLock(wr.Target); + ret.AddNoLock(pt); } } } @@ -1270,8 +1267,8 @@ public static PythonDictionary __prepare__([ParamDictionary]IDictionary /// Internal helper function to add a subtype /// private void AddSubType(PythonType subtype) { if (_subtypes == null) { - Interlocked.CompareExchange>(ref _subtypes, new List(), null); + Interlocked.CompareExchange(ref _subtypes, new List>(), null); } lock (_subtypesLock) { - _subtypes.Add(new WeakReference(subtype)); + if (_subtypes.Count == _subtypes.Capacity) { + _subtypes.RemoveAll(x => !x.TryGetTarget(out _)); // remove dead entries + } + _subtypes.Add(new WeakReference(subtype)); } } private void RemoveSubType(PythonType subtype) { - int i = 0; - if (_subtypes != null) { - lock (_subtypesLock) { - while (i < _subtypes.Count) { - if (!_subtypes[i].IsAlive || _subtypes[i].Target == subtype) { - _subtypes.RemoveAt(i); - continue; - } - i++; + if (_subtypes is null) return; + + lock (_subtypesLock) { + int i = 0; + while (i < _subtypes.Count) { + var wr = _subtypes[i]; + if (!wr.TryGetTarget(out PythonType target) || target == subtype) { + _subtypes.RemoveAt(i); + continue; } + i++; } } } @@ -2530,9 +2531,9 @@ public static PythonDictionary __prepare__([ParamDictionary]IDictionary - private IList SubTypes { + private IList> SubTypes { get { - if (_subtypes == null) return _emptyWeakRef; + if (_subtypes == null) return Array.Empty>(); lock (_subtypesLock) { return _subtypes.ToArray(); diff --git a/Src/IronPythonTest/Cases/IronPythonCasesManifest.ini b/Src/IronPythonTest/Cases/IronPythonCasesManifest.ini index 02e23cc1c..f63aa1863 100644 --- a/Src/IronPythonTest/Cases/IronPythonCasesManifest.ini +++ b/Src/IronPythonTest/Cases/IronPythonCasesManifest.ini @@ -55,10 +55,9 @@ Ignore=true Reason=Assertion error [IronPython.test_memory] -#RunCondition=NOT $(IS_POSIX) -#Reason=Memory allocation on Mono may not match MS.NET -Ignore=true -Reason=Fails intermittently - https://github.com/IronLanguages/ironpython3/issues/508 +IsolationLevel=PROCESS # to avoid having a long list of object subtypes +RunCondition=NOT $(IS_MONO) +Reason=Memory allocation on Mono may not match MS.NET [IronPython.test_number] Timeout=300000 # 5 minute timeout - slow on macOS diff --git a/Tests/test_memory.py b/Tests/test_memory.py index 48887d7d6..e4493b1a4 100644 --- a/Tests/test_memory.py +++ b/Tests/test_memory.py @@ -82,9 +82,9 @@ def setUp(self): from Microsoft.Scripting.Generation import Snippets self.skipMemoryCheck = Snippets.Shared.SaveSnippets or clr.GetCurrentRuntime().Configuration.DebugMode - self.expectedMem = 24000 # account for adaptive compilation + self.expectedMem = 24000 if is_cli64: self.expectedMem = int(self.expectedMem*1.25)