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

Skip to content

Commit 25a5c08

Browse files
authored
Dispose of ctypes to fix np.array holding on to memory for too long (fixes #108) (#109)
* Dispose of ctypes to fix np.array holding on to memory for too long (fixes #108) * Unit test for np.array memory disposal * Dispose of temporary array in the other path through np.array
1 parent b4708b4 commit 25a5c08

File tree

2 files changed

+47
-3
lines changed

2 files changed

+47
-3
lines changed

src/Numpy/Manual/np.array.cs

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ public static NDarray array(NDarray @object, Dtype dtype = null, bool? copy = nu
4242
if (subok != null) kwargs["subok"] = ToPython(subok);
4343
if (ndmin != null) kwargs["ndmin"] = ToPython(ndmin);
4444
dynamic py = self.InvokeMethod("array", args, kwargs);
45+
args.Dispose();
4546
return ToCsharp<NDarray>(py);
4647
}
4748

@@ -52,7 +53,8 @@ public static NDarray<T> array<T>(T[] @object, Dtype dtype = null, bool? copy =
5253
var ndarray = np.empty(new Shape(@object.Length), dtype: type, order: order);
5354
if (@object.Length == 0)
5455
return new NDarray<T>(ndarray);
55-
long ptr = ndarray.PyObject.ctypes.data;
56+
var ctypes = ndarray.PyObject.ctypes;
57+
long ptr = ctypes.data;
5658
switch ((object)@object)
5759
{
5860
case char[] a: Marshal.Copy(a, 0, new IntPtr(ptr), a.Length); break;
@@ -80,8 +82,13 @@ public static NDarray<T> array<T>(T[] @object, Dtype dtype = null, bool? copy =
8082
ndarray.imag = ndimag;
8183
break;
8284
}
83-
if (dtype !=null || subok != null || ndmin != null)
84-
return new NDarray<T>(np.array(ndarray, dtype:dtype, copy: false, subok: subok, ndmin: ndmin));
85+
ctypes.Dispose();
86+
if (dtype != null || subok != null || ndmin != null)
87+
{
88+
var converted = np.array(ndarray, dtype: dtype, copy: false, subok: subok, ndmin: ndmin);
89+
ndarray.Dispose();
90+
return new NDarray<T>(converted);
91+
}
8592
return new NDarray<T>(ndarray);
8693
}
8794

test/Numpy.UnitTest/NumPy_array_creation.tests.cs

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -355,6 +355,43 @@ public void full_likeTest()
355355
#endif
356356
}
357357

358+
[TestMethod]
359+
public void arrayLeakTest()
360+
{
361+
var arr = new double[10_000_000];
362+
using (var process = System.Diagnostics.Process.GetCurrentProcess())
363+
{
364+
long memStart;
365+
long getMemAfterGc()
366+
{
367+
GC.Collect(2, GCCollectionMode.Forced, true, true);
368+
process.Refresh();
369+
return process.PrivateMemorySize64;
370+
}
371+
long getOutstandingMem() => getMemAfterGc() - memStart;
372+
373+
var ones = np.ones(10_000_000); // python runtime warmup
374+
ones.Dispose();
375+
376+
memStart = getMemAfterGc();
377+
378+
ones = np.ones(10_000_000);
379+
Assert.IsTrue(getOutstandingMem() > 70_000_000);
380+
ones.Dispose();
381+
Assert.IsTrue(getOutstandingMem() < 1_000_000);
382+
383+
var array = np.array(arr);
384+
Assert.IsTrue(getOutstandingMem() > 70_000_000);
385+
array.Dispose();
386+
Assert.IsTrue(getOutstandingMem() < 1_000_000);
387+
388+
array = np.array(arr, np.float32);
389+
Assert.IsTrue(getOutstandingMem() > 30_000_000);
390+
array.Dispose();
391+
Assert.IsTrue(getOutstandingMem() < 1_000_000);
392+
}
393+
}
394+
358395
[TestMethod]
359396
public void arrayTest()
360397
{

0 commit comments

Comments
 (0)