Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit45c370a

Browse files
committed
fixed CollectBasicObject by ensuring MakeAGarbage is not keeping temp object alive
1 parentce76f2e commit45c370a

File tree

3 files changed

+46
-55
lines changed

3 files changed

+46
-55
lines changed

‎src/embed_tests/TestFinalizer.cs

Lines changed: 32 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@
22
usingPython.Runtime;
33
usingSystem;
44
usingSystem.Collections.Generic;
5-
usingSystem.ComponentModel;
65
usingSystem.Diagnostics;
76
usingSystem.Linq;
7+
usingSystem.Runtime.CompilerServices;
88
usingSystem.Threading;
99

1010
namespacePython.EmbeddingTest
@@ -28,26 +28,14 @@ public void TearDown()
2828
PythonEngine.Shutdown();
2929
}
3030

31-
privatestaticboolFullGCCollect()
31+
privatestaticvoidFullGCCollect()
3232
{
33-
GC.Collect(GC.MaxGeneration,GCCollectionMode.Forced);
34-
try
35-
{
36-
returnGC.WaitForFullGCComplete()==GCNotificationStatus.Succeeded;
37-
}
38-
catch(NotImplementedException)
39-
{
40-
// Some clr runtime didn't implement GC.WaitForFullGCComplete yet.
41-
returnfalse;
42-
}
43-
finally
44-
{
45-
GC.WaitForPendingFinalizers();
46-
}
33+
GC.Collect();
34+
GC.WaitForPendingFinalizers();
4735
}
4836

4937
[Test]
50-
[Ignore("Ignore temporarily")]
38+
[Obsolete("GC tests are not guaranteed")]
5139
publicvoidCollectBasicObject()
5240
{
5341
Assert.IsTrue(Finalizer.Instance.Enable);
@@ -104,18 +92,13 @@ public void CollectBasicObject()
10492
}
10593

10694
[Test]
107-
[Ignore("Ignore temporarily")]
95+
[Obsolete("GC tests are not guaranteed")]
10896
publicvoidCollectOnShutdown()
10997
{
11098
IntPtrop=MakeAGarbage(outvarshortWeak,outvarlongWeak);
111-
inthash=shortWeak.Target.GetHashCode();
112-
List<WeakReference>garbage;
113-
if(!FullGCCollect())
114-
{
115-
Assert.IsTrue(WaitForCollected(op,hash,10000));
116-
}
99+
FullGCCollect();
117100
Assert.IsFalse(shortWeak.IsAlive);
118-
garbage=Finalizer.Instance.GetCollectedObjects();
101+
List<WeakReference>garbage=Finalizer.Instance.GetCollectedObjects();
119102
Assert.IsNotEmpty(garbage,"The garbage object should be collected");
120103
Assert.IsTrue(garbage.Any(r=>ReferenceEquals(r.Target,longWeak.Target)),
121104
"Garbage should contains the collected object");
@@ -125,12 +108,29 @@ public void CollectOnShutdown()
125108
Assert.IsEmpty(garbage);
126109
}
127110

111+
[MethodImpl(MethodImplOptions.NoInlining|MethodImplOptions.NoOptimization)]// ensure lack of references to obj
112+
[Obsolete("GC tests are not guaranteed")]
128113
privatestaticIntPtrMakeAGarbage(outWeakReferenceshortWeak,outWeakReferencelongWeak)
129114
{
130-
PyLongobj=newPyLong(1024);
131-
shortWeak=newWeakReference(obj);
132-
longWeak=newWeakReference(obj,true);
133-
returnobj.Handle;
115+
IntPtrhandle=IntPtr.Zero;
116+
WeakReference@short=null,@long=null;
117+
// must create Python object in the thread where we have GIL
118+
IntPtrval=PyLong.FromLong(1024);
119+
// must create temp object in a different thread to ensure it is not present
120+
// when conservatively scanning stack for GC roots.
121+
// see https://xamarin.github.io/bugzilla-archives/17/17593/bug.html
122+
vargarbageGen=newThread(()=>
123+
{
124+
varobj=newPyObject(val,skipCollect:true);
125+
@short=newWeakReference(obj);
126+
@long=newWeakReference(obj,true);
127+
handle=obj.Handle;
128+
});
129+
garbageGen.Start();
130+
Assert.IsTrue(garbageGen.Join(TimeSpan.FromSeconds(5)),"Garbage creation timed out");
131+
shortWeak=@short;
132+
longWeak=@long;
133+
returnhandle;
134134
}
135135

136136
privatestaticlongCompareWithFinalizerOn(PyObjectpyCollect,boolenbale)
@@ -211,6 +211,7 @@ internal static void CreateMyPyObject(IntPtr op)
211211
}
212212

213213
[Test]
214+
[Obsolete("GC tests are not guaranteed")]
214215
publicvoidErrorHandling()
215216
{
216217
boolcalled=false;
@@ -228,7 +229,7 @@ public void ErrorHandling()
228229
WeakReferencelongWeak;
229230
{
230231
MakeAGarbage(outshortWeak,outlongWeak);
231-
varobj=(PyLong)longWeak.Target;
232+
varobj=(PyObject)longWeak.Target;
232233
IntPtrhandle=obj.Handle;
233234
shortWeak=null;
234235
longWeak=null;
@@ -279,36 +280,13 @@ public void ValidateRefCount()
279280
}
280281
}
281282

283+
[MethodImpl(MethodImplOptions.NoInlining|MethodImplOptions.NoOptimization)]// ensure lack of references to s1 and s2
282284
privatestaticIntPtrCreateStringGarbage()
283285
{
284286
PyStrings1=newPyString("test_string");
285287
// s2 steal a reference from s1
286288
PyStrings2=newPyString(s1.Handle);
287289
returns1.Handle;
288290
}
289-
290-
privatestaticboolWaitForCollected(IntPtrop,inthash,intmilliseconds)
291-
{
292-
varstopwatch=Stopwatch.StartNew();
293-
do
294-
{
295-
vargarbage=Finalizer.Instance.GetCollectedObjects();
296-
foreach(varitemingarbage)
297-
{
298-
// The validation is not 100% precise,
299-
// but it's rare that two conditions satisfied but they're still not the same object.
300-
if(item.Target.GetHashCode()!=hash)
301-
{
302-
continue;
303-
}
304-
varobj=(IPyDisposable)item.Target;
305-
if(obj.GetTrackedHandles().Contains(op))
306-
{
307-
returntrue;
308-
}
309-
}
310-
}while(stopwatch.ElapsedMilliseconds<milliseconds);
311-
returnfalse;
312-
}
313291
}
314292
}

‎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-
privatestaticIntPtrFromLong(longvalue)
77+
internalstaticIntPtrFromLong(longvalue)
7878
{
7979
IntPtrval=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("for testing purposes only")]
58+
internalPyObject(IntPtrptr,boolskipCollect)
59+
{
60+
if(ptr==IntPtr.Zero)thrownewArgumentNullException(nameof(ptr));
61+
62+
obj=ptr;
63+
if(!skipCollect)
64+
Finalizer.Instance.ThrottledCollect();
65+
#ifTRACE_ALLOC
66+
Traceback=newStackTrace(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)

[8]ページ先頭

©2009-2025 Movatter.jp