Skip to content

Commit 356d76f

Browse files
greateggsgregfilmor
authored andcommitted
Harden CollectBasicObject against .NET-GC timing differences
1 parent fda8211 commit 356d76f

1 file changed

Lines changed: 20 additions & 19 deletions

File tree

src/embed_tests/TestFinalizer.cs

Lines changed: 20 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ private static void FullGCCollect()
3030
{
3131
GC.Collect();
3232
GC.WaitForPendingFinalizers();
33+
GC.Collect(); // reclaim objects whose finalizers just ran
3334
}
3435

3536
[Test]
@@ -51,28 +52,28 @@ public void CollectBasicObject()
5152
Finalizer.Instance.BeforeCollect += handler;
5253

5354
IntPtr pyObj = MakeAGarbage(out var shortWeak, out var longWeak);
54-
FullGCCollect();
55-
// The object has been resurrected
56-
Warn.If(
57-
shortWeak.IsAlive,
58-
"The referenced object is alive although it should have been collected",
59-
shortWeak
60-
);
61-
Assert.That(
62-
longWeak.IsAlive,
63-
Is.True,
64-
$"The reference object is not alive although it should still be"
65-
);
6655

56+
// The real contract: after the wrapper is GC'd, the underlying
57+
// Python pointer must end up in Finalizer's queue. Poll because
58+
// .NET Framework / .NET Core differ in how many GC cycles it takes.
59+
List<IntPtr> garbage = null;
60+
for (int attempt = 0; attempt < 10; attempt++)
6761
{
68-
var garbage = Finalizer.Instance.GetCollectedObjects();
69-
Assert.NotZero(garbage.Count, "There should still be garbage around");
70-
Warn.Unless(
71-
garbage.Contains(pyObj),
72-
$"The {nameof(longWeak)} reference doesn't show up in the garbage list",
73-
garbage
74-
);
62+
FullGCCollect();
63+
garbage = Finalizer.Instance.GetCollectedObjects();
64+
if (garbage.Contains(pyObj)) break;
65+
Thread.Sleep(20);
7566
}
67+
68+
Warn.If(shortWeak.IsAlive,
69+
"shortWeak is alive after FullGCCollect; runtime hasn't reclaimed the wrapper yet",
70+
shortWeak);
71+
// longWeak.IsAlive at this point is .NET-GC-implementation-defined
72+
// (Framework reclaims post-finalize objects more eagerly than Core);
73+
// intentionally not asserted.
74+
75+
Assert.That(garbage, Has.Member(pyObj),
76+
"PyObject did not reach Finalizer.Instance.GetCollectedObjects()");
7677
try
7778
{
7879
Finalizer.Instance.Collect();

0 commit comments

Comments
 (0)