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

Commit6bc85ff

Browse files
authored
Merge pull request#1313 from losttech/bugs/1309
Fixed CollectBasicObject test
2 parentsc23958e +ca96444 commit6bc85ff

File tree

10 files changed

+132
-211
lines changed

10 files changed

+132
-211
lines changed

‎src/embed_tests/TestDomainReload.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -191,7 +191,7 @@ from Python.EmbeddingTest.Domain import MyClass
191191
def test_obj_call():
192192
obj = MyClass()
193193
obj.Method()
194-
obj.StaticMethod()
194+
MyClass.StaticMethod()
195195
obj.Property = 1
196196
obj.Field = 10
197197
@@ -288,7 +288,7 @@ void ExecTest()
288288

289289
GC.Collect();
290290
GC.WaitForPendingFinalizers();// <- this will put former `num` into Finalizer queue
291-
Finalizer.Instance.Collect(forceDispose:true);
291+
Finalizer.Instance.Collect();
292292
// ^- this will call PyObject.Dispose, which will call XDecref on `num.Handle`,
293293
// but Python interpreter from "run" 1 is long gone, so it will corrupt memory instead.
294294
Assert.False(numRef.IsAlive);
@@ -333,7 +333,7 @@ void ExecTest()
333333
PythonEngine.Initialize();// <- "run" 2 starts
334334
GC.Collect();
335335
GC.WaitForPendingFinalizers();
336-
Finalizer.Instance.Collect(forceDispose:true);
336+
Finalizer.Instance.Collect();
337337
Assert.False(objRef.IsAlive);
338338
}
339339
finally

‎src/embed_tests/TestFinalizer.cs

Lines changed: 33 additions & 116 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);
@@ -64,11 +52,7 @@ public void CollectBasicObject()
6452
Assert.IsFalse(called,"The event handler was called before it was installed");
6553
Finalizer.Instance.CollectOnce+=handler;
6654

67-
WeakReferenceshortWeak;
68-
WeakReferencelongWeak;
69-
{
70-
MakeAGarbage(outshortWeak,outlongWeak);
71-
}
55+
IntPtrpyObj=MakeAGarbage(outvarshortWeak,outvarlongWeak);
7256
FullGCCollect();
7357
// The object has been resurrected
7458
Warn.If(
@@ -86,7 +70,7 @@ public void CollectBasicObject()
8670
vargarbage=Finalizer.Instance.GetCollectedObjects();
8771
Assert.NotZero(garbage.Count,"There should still be garbage around");
8872
Warn.Unless(
89-
garbage.Any(T=>ReferenceEquals(T.Target,longWeak.Target)),
73+
garbage.Contains(pyObj),
9074
$"The{nameof(longWeak)} reference doesn't show up in the garbage list",
9175
garbage
9276
);
@@ -104,33 +88,45 @@ public void CollectBasicObject()
10488
}
10589

10690
[Test]
107-
[Ignore("Ignore temporarily")]
91+
[Obsolete("GC tests are not guaranteed")]
10892
publicvoidCollectOnShutdown()
10993
{
11094
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-
}
95+
FullGCCollect();
11796
Assert.IsFalse(shortWeak.IsAlive);
118-
garbage=Finalizer.Instance.GetCollectedObjects();
97+
List<IntPtr>garbage=Finalizer.Instance.GetCollectedObjects();
11998
Assert.IsNotEmpty(garbage,"The garbage object should be collected");
120-
Assert.IsTrue(garbage.Any(r=>ReferenceEquals(r.Target,longWeak.Target)),
99+
Assert.IsTrue(garbage.Contains(op),
121100
"Garbage should contains the collected object");
122101

123102
PythonEngine.Shutdown();
124103
garbage=Finalizer.Instance.GetCollectedObjects();
125104
Assert.IsEmpty(garbage);
126105
}
127106

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

136132
privatestaticlongCompareWithFinalizerOn(PyObjectpyCollect,boolenbale)
@@ -191,62 +187,6 @@ public void SimpleTestMemory()
191187
}
192188
}
193189

194-
classMyPyObject:PyObject
195-
{
196-
publicMyPyObject(IntPtrop):base(op)
197-
{
198-
}
199-
200-
protectedoverridevoidDispose(booldisposing)
201-
{
202-
base.Dispose(disposing);
203-
GC.SuppressFinalize(this);
204-
thrownewException("MyPyObject");
205-
}
206-
internalstaticvoidCreateMyPyObject(IntPtrop)
207-
{
208-
Runtime.Runtime.XIncref(op);
209-
newMyPyObject(op);
210-
}
211-
}
212-
213-
[Test]
214-
publicvoidErrorHandling()
215-
{
216-
boolcalled=false;
217-
varerrorMessage="";
218-
EventHandler<Finalizer.ErrorArgs>handleFunc=(sender,args)=>
219-
{
220-
called=true;
221-
errorMessage=args.Error.Message;
222-
};
223-
Finalizer.Instance.Threshold=1;
224-
Finalizer.Instance.ErrorHandler+=handleFunc;
225-
try
226-
{
227-
WeakReferenceshortWeak;
228-
WeakReferencelongWeak;
229-
{
230-
MakeAGarbage(outshortWeak,outlongWeak);
231-
varobj=(PyLong)longWeak.Target;
232-
IntPtrhandle=obj.Handle;
233-
shortWeak=null;
234-
longWeak=null;
235-
MyPyObject.CreateMyPyObject(handle);
236-
obj.Dispose();
237-
obj=null;
238-
}
239-
FullGCCollect();
240-
Finalizer.Instance.Collect();
241-
Assert.IsTrue(called);
242-
}
243-
finally
244-
{
245-
Finalizer.Instance.ErrorHandler-=handleFunc;
246-
}
247-
Assert.AreEqual(errorMessage,"MyPyObject");
248-
}
249-
250190
[Test]
251191
publicvoidValidateRefCount()
252192
{
@@ -279,36 +219,13 @@ public void ValidateRefCount()
279219
}
280220
}
281221

222+
[MethodImpl(MethodImplOptions.NoInlining|MethodImplOptions.NoOptimization)]// ensure lack of references to s1 and s2
282223
privatestaticIntPtrCreateStringGarbage()
283224
{
284225
PyStrings1=newPyString("test_string");
285226
// s2 steal a reference from s1
286227
PyStrings2=newPyString(s1.Handle);
287228
returns1.Handle;
288229
}
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-
}
313230
}
314231
}

‎src/runtime/debughelper.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,5 +137,12 @@ public static void PrintHexBytes(byte[] bytes)
137137
Console.WriteLine();
138138
}
139139
}
140+
141+
[Conditional("DEBUG")]
142+
publicstaticvoidAssertHasReferences(IntPtrobj)
143+
{
144+
longrefcount=Runtime.Refcount(obj);
145+
Debug.Assert(refcount>0,"Object refcount is 0 or less");
146+
}
140147
}
141148
}

‎src/runtime/delegatemanager.cs

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -181,7 +181,7 @@ A possible alternate strategy would be to create custom subclasses
181181
too "special" for this to work. It would be more work, so for now
182182
the 80/20 rule applies :) */
183183

184-
publicclassDispatcher:IPyDisposable
184+
publicclassDispatcher
185185
{
186186
publicIntPtrtarget;
187187
publicTypedtype;
@@ -202,7 +202,7 @@ public Dispatcher(IntPtr target, Type dtype)
202202
return;
203203
}
204204
_finalized=true;
205-
Finalizer.Instance.AddFinalizedObject(this);
205+
Finalizer.Instance.AddFinalizedObject(reftarget);
206206
}
207207

208208
publicvoidDispose()
@@ -276,11 +276,6 @@ public object TrueDispatch(ArrayList args)
276276
Runtime.XDecref(op);
277277
returnresult;
278278
}
279-
280-
publicIntPtr[]GetTrackedHandles()
281-
{
282-
returnnewIntPtr[]{target};
283-
}
284279
}
285280

286281

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp