🌐 AI搜索 & 代理 主页
Skip to content

Commit 8d89411

Browse files
committed
dropped WaitForFullGCComplete, as GC.Collect is blocking
1 parent 002d730 commit 8d89411

File tree

3 files changed

+47
-53
lines changed

3 files changed

+47
-53
lines changed

src/embed_tests/TestFinalizer.cs

Lines changed: 33 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -28,25 +28,16 @@ public void TearDown()
2828
PythonEngine.Shutdown();
2929
}
3030

31-
private static bool FullGCCollect()
31+
private static void FullGCCollect()
3232
{
33-
GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced);
34-
try
35-
{
36-
return GC.WaitForFullGCComplete() == GCNotificationStatus.Succeeded;
37-
}
38-
catch (NotImplementedException)
39-
{
40-
// Some clr runtime didn't implement GC.WaitForFullGCComplete yet.
41-
return false;
42-
}
43-
finally
44-
{
45-
GC.WaitForPendingFinalizers();
46-
}
33+
Thread.MemoryBarrier();
34+
GC.Collect();
35+
GC.WaitForPendingFinalizers();
36+
Thread.MemoryBarrier();
4737
}
4838

4939
[Test]
40+
[Obsolete("GC tests are not guaranteed")]
5041
public void CollectBasicObject()
5142
{
5243
Assert.IsTrue(Finalizer.Instance.Enable);
@@ -103,17 +94,13 @@ public void CollectBasicObject()
10394
}
10495

10596
[Test]
97+
[Obsolete("GC tests are not guaranteed")]
10698
public void CollectOnShutdown()
10799
{
108100
IntPtr op = MakeAGarbage(out var shortWeak, out var longWeak);
109-
int hash = shortWeak.Target.GetHashCode();
110-
List<WeakReference> garbage;
111-
if (!FullGCCollect())
112-
{
113-
Assert.IsTrue(WaitForCollected(op, hash, 10000));
114-
}
101+
FullGCCollect();
115102
Assert.IsFalse(shortWeak.IsAlive);
116-
garbage = Finalizer.Instance.GetCollectedObjects();
103+
List<WeakReference> garbage = Finalizer.Instance.GetCollectedObjects();
117104
Assert.IsNotEmpty(garbage, "The garbage object should be collected");
118105
Assert.IsTrue(garbage.Any(r => ReferenceEquals(r.Target, longWeak.Target)),
119106
"Garbage should contains the collected object");
@@ -123,13 +110,29 @@ public void CollectOnShutdown()
123110
Assert.IsEmpty(garbage);
124111
}
125112

126-
[MethodImpl(MethodImplOptions.NoInlining)] // ensure lack of references to obj
113+
[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.NoOptimization)] // ensure lack of references to obj
114+
[Obsolete("GC tests are not guaranteed")]
127115
private static IntPtr MakeAGarbage(out WeakReference shortWeak, out WeakReference longWeak)
128116
{
129-
PyLong obj = new PyLong(1024);
130-
shortWeak = new WeakReference(obj);
131-
longWeak = new WeakReference(obj, true);
132-
return obj.Handle;
117+
IntPtr handle = IntPtr.Zero;
118+
WeakReference @short = null, @long = null;
119+
// must create Python object in the thread where we have GIL
120+
IntPtr val = PyLong.FromLong(1024);
121+
// must create temp object in a different thread to ensure it is not present
122+
// when conservatively scanning stack for GC roots.
123+
// see https://xamarin.github.io/bugzilla-archives/17/17593/bug.html
124+
var garbageGen = new Thread(() =>
125+
{
126+
var obj = new PyObject(val, skipCollect: true);
127+
@short = new WeakReference(obj);
128+
@long = new WeakReference(obj, true);
129+
handle = obj.Handle;
130+
});
131+
garbageGen.Start();
132+
Assert.IsTrue(garbageGen.Join(TimeSpan.FromSeconds(5)), "Garbage creation timed out");
133+
shortWeak = @short;
134+
longWeak = @long;
135+
return handle;
133136
}
134137

135138
private static long CompareWithFinalizerOn(PyObject pyCollect, bool enbale)
@@ -210,6 +213,7 @@ internal static void CreateMyPyObject(IntPtr op)
210213
}
211214

212215
[Test]
216+
[Obsolete("GC tests are not guaranteed")]
213217
public void ErrorHandling()
214218
{
215219
bool called = false;
@@ -227,7 +231,7 @@ public void ErrorHandling()
227231
WeakReference longWeak;
228232
{
229233
MakeAGarbage(out shortWeak, out longWeak);
230-
var obj = (PyLong)longWeak.Target;
234+
var obj = (PyObject)longWeak.Target;
231235
IntPtr handle = obj.Handle;
232236
shortWeak = null;
233237
longWeak = null;
@@ -278,36 +282,13 @@ public void ValidateRefCount()
278282
}
279283
}
280284

285+
[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.NoOptimization)] // ensure lack of references to s1 and s2
281286
private static IntPtr CreateStringGarbage()
282287
{
283288
PyString s1 = new PyString("test_string");
284289
// s2 steal a reference from s1
285290
PyString s2 = new PyString(s1.Handle);
286291
return s1.Handle;
287292
}
288-
289-
private static bool WaitForCollected(IntPtr op, int hash, int milliseconds)
290-
{
291-
var stopwatch = Stopwatch.StartNew();
292-
do
293-
{
294-
var garbage = Finalizer.Instance.GetCollectedObjects();
295-
foreach (var item in garbage)
296-
{
297-
// The validation is not 100% precise,
298-
// but it's rare that two conditions satisfied but they're still not the same object.
299-
if (item.Target.GetHashCode() != hash)
300-
{
301-
continue;
302-
}
303-
var obj = (IPyDisposable)item.Target;
304-
if (obj.GetTrackedHandles().Contains(op))
305-
{
306-
return true;
307-
}
308-
}
309-
} while (stopwatch.ElapsedMilliseconds < milliseconds);
310-
return false;
311-
}
312293
}
313294
}

src/runtime/pylong.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ public PyLong(uint value) : base(FromInt((int)value))
7474
}
7575

7676

77-
private static IntPtr FromLong(long value)
77+
internal static IntPtr FromLong(long value)
7878
{
7979
IntPtr val = Runtime.PyLong_FromLongLong(value);
8080
PythonException.ThrowIfIsNull(val);

src/runtime/pyobject.cs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,19 @@ public PyObject(IntPtr ptr)
5454
#endif
5555
}
5656

57+
[Obsolete("this is for testing purposes only")]
58+
internal PyObject(IntPtr ptr, bool skipCollect)
59+
{
60+
if (ptr == IntPtr.Zero) throw new ArgumentNullException(nameof(ptr));
61+
62+
obj = ptr;
63+
if (!skipCollect)
64+
Finalizer.Instance.ThrottledCollect();
65+
#if TRACE_ALLOC
66+
Traceback = new StackTrace(1);
67+
#endif
68+
}
69+
5770
/// <summary>
5871
/// Creates new <see cref="PyObject"/> pointing to the same object as
5972
/// the <paramref name="reference"/>. Increments refcount, allowing <see cref="PyObject"/>

0 commit comments

Comments
 (0)