From 1fae108ef67a88873d4a793abf849b212c126ab9 Mon Sep 17 00:00:00 2001 From: amos402 Date: Thu, 18 Oct 2018 22:59:43 +0800 Subject: [PATCH] Reset gchead and refchain after shutdown --- src/runtime/pythonengine.cs | 69 ++++++++++++++++++++++++++++++++++++- src/runtime/runtime.cs | 6 +++- 2 files changed, 73 insertions(+), 2 deletions(-) diff --git a/src/runtime/pythonengine.cs b/src/runtime/pythonengine.cs index a23c7ac79..3a5032cb4 100644 --- a/src/runtime/pythonengine.cs +++ b/src/runtime/pythonengine.cs @@ -1,5 +1,6 @@ -using System; +using System; using System.Collections.Generic; +using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; @@ -12,11 +13,16 @@ namespace Python.Runtime /// public class PythonEngine : IDisposable { + private const int NUM_GENERATIONS = 3; + private static DelegateManager delegateManager; private static bool initialized; private static IntPtr _pythonHome = IntPtr.Zero; private static IntPtr _programName = IntPtr.Zero; private static IntPtr _pythonPath = IntPtr.Zero; + private static IntPtr _refChain = IntPtr.Zero; + private static IntPtr[] _generations; + public PythonEngine() { @@ -168,6 +174,10 @@ public static void Initialize(IEnumerable args, bool setSysArgv = true) initialized = true; Exceptions.Clear(); + _generations = GetGCGenerations(); +#if PYTHON_WITH_PYDEBUG + _refChain = GetRefChainHead(); +#endif if (setSysArgv) { Py.SetArgv(args); @@ -303,6 +313,7 @@ public static void Shutdown() _pythonPath = IntPtr.Zero; Runtime.Shutdown(); + ResetGC(); initialized = false; } } @@ -520,6 +531,62 @@ internal static PyObject RunString(string code, IntPtr? globals, IntPtr? locals, } } } + + internal static void ResetGC() + { + ClearGC(); +#if PYTHON_WITH_PYDEBUG + ResetRefChain(); +#endif + } + + private static void ClearGC() + { + Debug.Assert(_generations != null); + foreach (IntPtr head in _generations) + { + // gc.gc_next + Marshal.WriteIntPtr(head, 0, head); + // gc.gc_prev + Marshal.WriteIntPtr(head, IntPtr.Size, head); + } + } + + private static IntPtr[] GetGCGenerations() + { + int GCHeadOffset = IntPtr.Size == 4 ? 24 : 32; + IntPtr op = Runtime._PyObject_GC_New(Runtime.PyTypeType); + Runtime.PyObject_GC_Track(op); + IntPtr g = Runtime._Py_AS_GC(op); + // According to _PyObjct_GC_TRACK and PyGC_Head strcture, g is the g->gc.gc_next + // It also become the GEN_HEAD(0) now + IntPtr[] gens = new IntPtr[NUM_GENERATIONS]; + for (int i = 0; i < NUM_GENERATIONS; i++) + { + gens[i] = g; + g += GCHeadOffset; + } + Runtime.PyObject_GC_UnTrack(op); + Runtime.PyObject_GC_Del(op); + return gens; + } + +#if PYTHON_WITH_PYDEBUG + private static void ResetRefChain() + { + Debug.Assert(_refChain != IntPtr.Zero); + Marshal.WriteIntPtr(_refChain, ObjectOffset._ob_next, _refChain); + Marshal.WriteIntPtr(_refChain, ObjectOffset._ob_prev, _refChain); + } + + private static IntPtr GetRefChainHead() + { + IntPtr op = Runtime._PyObject_GC_New(Runtime.PyBaseObjectType); + IntPtr refchain = Marshal.ReadIntPtr(op, ObjectOffset._ob_prev); + Runtime.PyObject_GC_Del(op); + return refchain; + } +#endif } public enum RunFlagType diff --git a/src/runtime/runtime.cs b/src/runtime/runtime.cs index b4ddc7f7e..9c898e279 100644 --- a/src/runtime/runtime.cs +++ b/src/runtime/runtime.cs @@ -1575,7 +1575,7 @@ internal static bool PyObject_TypeCheck(IntPtr ob, IntPtr tp) internal static extern IntPtr _PyObject_GetDictPtr(IntPtr obj); [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - internal static extern IntPtr PyObject_GC_New(IntPtr tp); + internal static extern IntPtr _PyObject_GC_New(IntPtr tp); [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] internal static extern void PyObject_GC_Del(IntPtr tp); @@ -1600,6 +1600,10 @@ internal static bool PyObject_TypeCheck(IntPtr ob, IntPtr tp) [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] internal static extern void PyMem_Free(IntPtr ptr); + internal static IntPtr _Py_AS_GC(IntPtr op) + { + return op - IntPtr.Size; + } //==================================================================== // Python exception API pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy