Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 885cd3e

Browse files
Fix memory leak in finalizer
- `finalizer` was leaking `_pendingArgs` (global memory) when the call to `Py_AddPendingCall` was unsuccessful. - Changing `lock` for `Monitor.TryEnter` at `AddPendingCollect()` so threads don't block each other.
1 parent f83c884 commit 885cd3e

File tree

1 file changed

+30
-20
lines changed

1 file changed

+30
-20
lines changed

src/runtime/finalizer.cs

Lines changed: 30 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ struct PendingArgs
4141
private ConcurrentQueue<IPyDisposable> _objQueue = new ConcurrentQueue<IPyDisposable>();
4242
private bool _pending = false;
4343
private readonly object _collectingLock = new object();
44-
private IntPtr _pendingArgs;
44+
private IntPtr _pendingArgs = IntPtr.Zero;
4545

4646
#region FINALIZER_CHECK
4747

@@ -128,7 +128,7 @@ internal void AddFinalizedObject(IPyDisposable obj)
128128
_objQueue.Enqueue(obj);
129129
}
130130
GC.ReRegisterForFinalize(obj);
131-
if (_objQueue.Count >= Threshold)
131+
if (!_pending && _objQueue.Count >= Threshold)
132132
{
133133
AddPendingCollect();
134134
}
@@ -164,26 +164,28 @@ internal static void Shutdown()
164164

165165
private void AddPendingCollect()
166166
{
167-
if (_pending)
167+
if(Monitor.TryEnter(_collectingLock))
168168
{
169-
return;
170-
}
171-
lock (_collectingLock)
172-
{
173-
if (_pending)
169+
try
174170
{
175-
return;
171+
if (!_pending)
172+
{
173+
_pending = true;
174+
var args = new PendingArgs { cancelled = false };
175+
_pendingArgs = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(PendingArgs)));
176+
Marshal.StructureToPtr(args, _pendingArgs, false);
177+
IntPtr func = Marshal.GetFunctionPointerForDelegate(_collectAction);
178+
if (Runtime.Py_AddPendingCall(func, _pendingArgs) != 0)
179+
{
180+
// Full queue, append next time
181+
FreePendingArgs();
182+
_pending = false;
183+
}
184+
}
176185
}
177-
_pending = true;
178-
var args = new PendingArgs() { cancelled = false };
179-
IntPtr p = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(PendingArgs)));
180-
Marshal.StructureToPtr(args, p, false);
181-
_pendingArgs = p;
182-
IntPtr func = Marshal.GetFunctionPointerForDelegate(_collectAction);
183-
if (Runtime.Py_AddPendingCall(func, p) != 0)
186+
finally
184187
{
185-
// Full queue, append next time
186-
_pending = false;
188+
Monitor.Exit(_collectingLock);
187189
}
188190
}
189191
}
@@ -205,8 +207,8 @@ private static int OnPendingCollect(IntPtr arg)
205207
}
206208
finally
207209
{
210+
Instance.FreePendingArgs();
208211
Instance.ResetPending();
209-
Marshal.FreeHGlobal(arg);
210212
}
211213
return 0;
212214
}
@@ -244,12 +246,20 @@ private void DisposeAll()
244246
}
245247
}
246248

249+
private void FreePendingArgs()
250+
{
251+
if (_pendingArgs != IntPtr.Zero)
252+
{
253+
Marshal.FreeHGlobal(_pendingArgs);
254+
_pendingArgs = IntPtr.Zero;
255+
}
256+
}
257+
247258
private void ResetPending()
248259
{
249260
lock (_collectingLock)
250261
{
251262
_pending = false;
252-
_pendingArgs = IntPtr.Zero;
253263
}
254264
}
255265

0 commit comments

Comments
 (0)