Visitar URL original
Alternative attempt at fixing memleak by being explicit about copies by filmor · Pull Request #2722 · pythonnet/pythonnet · GitHub
Skip to content
Closed
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
Tighten leak-test threshold to 10% to actually fail the bug
The previous 90% threshold (0.9 MB/iter against a 1 MB allocation)
documented the issue but did not reproduce it: master leaks
~600-765 KB/iter, which the 0.9 MB threshold accepts as passing.

Drop the threshold to 10% (104 KB/iter). On the 2026-05-09 verification
run with Python 3.14 GIL on linux-aarch64:

  Without fix (master):   ~572-765 KB/iter (FAIL)
  With fix (this branch): ~-500 B/iter     (PASS)

Margin is roughly 6x in either direction across .NET 8 and .NET 10, so
the threshold cleanly separates buggy from fixed states without being
sensitive to GC noise.
  • Loading branch information
greateggsgreg authored and filmor committed May 11, 2026
commit 7f8a2475f970313251eefba38f597f16b8077660
15 changes: 8 additions & 7 deletions tests/test_method.py
Original file line number Diff line number Diff line change
Expand Up @@ -983,9 +983,10 @@ def test_getting_generic_method_binding_does_not_leak_memory(memory_usage_tracki
bytesAllocatedPerIteration = pow(2, 20) # 1MB
bytesLeakedPerIteration = processBytesDelta / iterations

# Allow 90% threshold - this shows the original issue is fixed, which leaks the full allocated bytes per iteration
# Increased from 50% to ensure that it works on Windows with Python >3.13
failThresholdBytesLeakedPerIteration = bytesAllocatedPerIteration * 0.9
# Tight 10% threshold: with the fix the per-iteration leak is essentially
# zero, while the bug retains the bulk of the 1 MB payload (~600 KB/iter
# on 3.14 GIL). 100 KB/iter cleanly distinguishes the two states.
failThresholdBytesLeakedPerIteration = bytesAllocatedPerIteration * 0.1

assert bytesLeakedPerIteration < failThresholdBytesLeakedPerIteration

Expand Down Expand Up @@ -1025,8 +1026,8 @@ def test_getting_overloaded_method_binding_does_not_leak_memory(memory_usage_tra
bytesAllocatedPerIteration = pow(2, 20) # 1MB
bytesLeakedPerIteration = processBytesDelta / iterations

# Allow 90% threshold - this shows the original issue is fixed, which leaks the full allocated bytes per iteration
failThresholdBytesLeakedPerIteration = bytesAllocatedPerIteration * 0.9
# Tight 10% threshold; see test_getting_generic_method_binding_does_not_leak_memory.
failThresholdBytesLeakedPerIteration = bytesAllocatedPerIteration * 0.1

assert bytesLeakedPerIteration < failThresholdBytesLeakedPerIteration

Expand Down Expand Up @@ -1068,8 +1069,8 @@ def test_getting_method_overloads_binding_does_not_leak_memory(memory_usage_trac
bytesAllocatedPerIteration = pow(2, 20) # 1MB
bytesLeakedPerIteration = processBytesDelta / iterations

# Allow 90% threshold - this shows the original issue is fixed, which leaks the full allocated bytes per iteration
failThresholdBytesLeakedPerIteration = bytesAllocatedPerIteration * 0.9
# Tight 10% threshold; see test_getting_generic_method_binding_does_not_leak_memory.
failThresholdBytesLeakedPerIteration = bytesAllocatedPerIteration * 0.1

assert bytesLeakedPerIteration < failThresholdBytesLeakedPerIteration

Expand Down
Loading