Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Skip Python GC on Windows 3.14 shutdown
  • Loading branch information
devtrack committed Jan 14, 2026
commit 302f1d2e38568e388406109ec8e3946a2dda97c8
1 change: 0 additions & 1 deletion .github/workflows/windows-build-test-3.14.yml
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,6 @@ jobs:
- name: Embedding tests (.NET Core)
run: dotnet test --runtime any-x64 --framework net8.0 --logger "console;verbosity=detailed" src/embed_tests/
if: always()
continue-on-error: true

- name: Python Tests (.NET Core)
run: pytest --runtime coreclr
Expand Down
14 changes: 14 additions & 0 deletions src/runtime/PythonEngine.cs
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,20 @@
get { return Marshal.PtrToStringAnsi(Runtime.Py_GetVersion()); }
}

internal static Version GetPythonVersion()
{
string? versionText = Version;
if (string.IsNullOrWhiteSpace(versionText))
{
return new Version(0, 0);
}

string versionPart = versionText.Split(' ')[0];
return Version.TryParse(versionPart, out Version? parsed)

Check failure on line 155 in src/runtime/PythonEngine.cs

View workflow job for this annotation

GitHub Actions / Build and Test

'string' does not contain a definition for 'TryParse' and no accessible extension method 'TryParse' accepting a first argument of type 'string' could be found (are you missing a using directive or an assembly reference?)

Check failure on line 155 in src/runtime/PythonEngine.cs

View workflow job for this annotation

GitHub Actions / Build and Test

'string' does not contain a definition for 'TryParse' and no accessible extension method 'TryParse' accepting a first argument of type 'string' could be found (are you missing a using directive or an assembly reference?)
? parsed
: new Version(0, 0);
}

public static string BuildInfo
{
get { return Marshal.PtrToStringAnsi(Runtime.Py_GetBuildInfo()); }
Expand Down
35 changes: 29 additions & 6 deletions src/runtime/Runtime.cs
Original file line number Diff line number Diff line change
Expand Up @@ -262,7 +262,7 @@
if (!HostedInPython && !ProcessIsTerminating)
{
// avoid saving dead objects
TryCollectingGarbage(runs: 3);
TryCollectingGarbage(runs: 3, pythonGC: !ShouldSkipPythonGcOnShutdown);

Check failure on line 265 in src/runtime/Runtime.cs

View workflow job for this annotation

GitHub Actions / Build and Test

There is no argument given that corresponds to the required parameter 'forceBreakLoops' of 'Runtime.TryCollectingGarbage(int, bool, bool, bool, bool, bool)'

Check failure on line 265 in src/runtime/Runtime.cs

View workflow job for this annotation

GitHub Actions / Build and Test

There is no argument given that corresponds to the required parameter 'forceBreakLoops' of 'Runtime.TryCollectingGarbage(int, bool, bool, bool, bool, bool)'

RuntimeData.Stash();
}
Expand All @@ -275,7 +275,8 @@
RemoveClrRootModule();

TryCollectingGarbage(MaxCollectRetriesOnShutdown, forceBreakLoops: true,
obj: true, derived: false, buffer: false);
obj: true, derived: false, buffer: false,
pythonGC: !ShouldSkipPythonGcOnShutdown);
CLRObject.creationBlocked = true;

NullGCHandles(ExtensionType.loadedExtensions);
Expand All @@ -294,8 +295,12 @@
DisposeLazyObject(hexCallable);
PyObjectConversions.Reset();

PyGC_Collect();
bool everythingSeemsCollected = TryCollectingGarbage(MaxCollectRetriesOnShutdown);
if (!ShouldSkipPythonGcOnShutdown)
{
PyGC_Collect();
}
bool everythingSeemsCollected = TryCollectingGarbage(MaxCollectRetriesOnShutdown,

Check failure on line 302 in src/runtime/Runtime.cs

View workflow job for this annotation

GitHub Actions / Build and Test

There is no argument given that corresponds to the required parameter 'forceBreakLoops' of 'Runtime.TryCollectingGarbage(int, bool, bool, bool, bool, bool)'

Check failure on line 302 in src/runtime/Runtime.cs

View workflow job for this annotation

GitHub Actions / Build and Test

There is no argument given that corresponds to the required parameter 'forceBreakLoops' of 'Runtime.TryCollectingGarbage(int, bool, bool, bool, bool, bool)'
pythonGC: !ShouldSkipPythonGcOnShutdown);
Debug.Assert(everythingSeemsCollected);

Finalizer.Shutdown();
Expand Down Expand Up @@ -328,7 +333,8 @@
const int MaxCollectRetriesOnShutdown = 20;
internal static int _collected;
static bool TryCollectingGarbage(int runs, bool forceBreakLoops,
bool obj = true, bool derived = true, bool buffer = true)
bool obj = true, bool derived = true, bool buffer = true,
bool pythonGC = true)
{
if (runs <= 0) throw new ArgumentOutOfRangeException(nameof(runs));

Expand All @@ -340,7 +346,10 @@
{
GC.Collect();
GC.WaitForPendingFinalizers();
pyCollected += PyGC_Collect();
if (pythonGC)
{
pyCollected += PyGC_Collect();
}
pyCollected += Finalizer.Instance.DisposeAll(disposeObj: obj,
disposeDerived: derived,
disposeBuffer: buffer);
Expand All @@ -366,6 +375,20 @@
public static bool TryCollectingGarbage(int runs)
=> TryCollectingGarbage(runs, forceBreakLoops: false);

static bool ShouldSkipPythonGcOnShutdown
{
get
{
if (!IsWindows)
{
return false;
}

Version version = PythonEngine.GetPythonVersion();
return version >= new Version(3, 14);
}
}

static void DisposeLazyObject(Lazy<PyObject> pyObject)
{
if (pyObject.IsValueCreated)
Expand Down
Loading