1
- using System ;
1
+ using System ;
2
2
using System . Collections . Generic ;
3
+ using System . Diagnostics ;
3
4
using System . IO ;
4
5
using System . Linq ;
5
6
using System . Reflection ;
@@ -12,11 +13,16 @@ namespace Python.Runtime
12
13
/// </summary>
13
14
public class PythonEngine : IDisposable
14
15
{
16
+ private const int NUM_GENERATIONS = 3 ;
17
+
15
18
private static DelegateManager delegateManager ;
16
19
private static bool initialized ;
17
20
private static IntPtr _pythonHome = IntPtr . Zero ;
18
21
private static IntPtr _programName = IntPtr . Zero ;
19
22
private static IntPtr _pythonPath = IntPtr . Zero ;
23
+ private static IntPtr _refChain = IntPtr . Zero ;
24
+ private static IntPtr [ ] _generations ;
25
+
20
26
21
27
public PythonEngine ( )
22
28
{
@@ -168,6 +174,10 @@ public static void Initialize(IEnumerable<string> args, bool setSysArgv = true)
168
174
initialized = true ;
169
175
Exceptions . Clear ( ) ;
170
176
177
+ _generations = GetGCGenerations ( ) ;
178
+ #if PYTHON_WITH_PYDEBUG
179
+ _refChain = GetRefChainHead ( ) ;
180
+ #endif
171
181
if ( setSysArgv )
172
182
{
173
183
Py . SetArgv ( args ) ;
@@ -303,6 +313,7 @@ public static void Shutdown()
303
313
_pythonPath = IntPtr . Zero ;
304
314
305
315
Runtime . Shutdown ( ) ;
316
+ ResetGC ( ) ;
306
317
initialized = false ;
307
318
}
308
319
}
@@ -520,6 +531,62 @@ internal static PyObject RunString(string code, IntPtr? globals, IntPtr? locals,
520
531
}
521
532
}
522
533
}
534
+
535
+ internal static void ResetGC ( )
536
+ {
537
+ ClearGC ( ) ;
538
+ #if PYTHON_WITH_PYDEBUG
539
+ ResetRefChain ( ) ;
540
+ #endif
541
+ }
542
+
543
+ private static void ClearGC ( )
544
+ {
545
+ Debug . Assert ( _generations != null ) ;
546
+ foreach ( IntPtr head in _generations )
547
+ {
548
+ // gc.gc_next
549
+ Marshal . WriteIntPtr ( head , 0 , head ) ;
550
+ // gc.gc_prev
551
+ Marshal . WriteIntPtr ( head , IntPtr . Size , head ) ;
552
+ }
553
+ }
554
+
555
+ private static IntPtr [ ] GetGCGenerations ( )
556
+ {
557
+ int GCHeadOffset = IntPtr . Size == 4 ? 24 : 32 ;
558
+ IntPtr op = Runtime . _PyObject_GC_New ( Runtime . PyTypeType ) ;
559
+ Runtime . PyObject_GC_Track ( op ) ;
560
+ IntPtr g = Runtime . _Py_AS_GC ( op ) ;
561
+ // According to _PyObjct_GC_TRACK and PyGC_Head strcture, g is the g->gc.gc_next
562
+ // It also become the GEN_HEAD(0) now
563
+ IntPtr [ ] gens = new IntPtr [ NUM_GENERATIONS ] ;
564
+ for ( int i = 0 ; i < NUM_GENERATIONS ; i ++ )
565
+ {
566
+ gens [ i ] = g ;
567
+ g += GCHeadOffset ;
568
+ }
569
+ Runtime . PyObject_GC_UnTrack ( op ) ;
570
+ Runtime . PyObject_GC_Del ( op ) ;
571
+ return gens ;
572
+ }
573
+
574
+ #if PYTHON_WITH_PYDEBUG
575
+ private static void ResetRefChain ( )
576
+ {
577
+ Debug . Assert ( _refChain != IntPtr . Zero ) ;
578
+ Marshal . WriteIntPtr ( _refChain , ObjectOffset . _ob_next , _refChain ) ;
579
+ Marshal . WriteIntPtr ( _refChain , ObjectOffset . _ob_prev , _refChain ) ;
580
+ }
581
+
582
+ private static IntPtr GetRefChainHead ( )
583
+ {
584
+ IntPtr op = Runtime . _PyObject_GC_New ( Runtime . PyBaseObjectType ) ;
585
+ IntPtr refchain = Marshal . ReadIntPtr ( op , ObjectOffset . _ob_prev ) ;
586
+ Runtime . PyObject_GC_Del ( op ) ;
587
+ return refchain ;
588
+ }
589
+ #endif
523
590
}
524
591
525
592
public enum RunFlagType
0 commit comments