From 4d006eb39d2eb1db13a3f7ce6e639ee715d4360e Mon Sep 17 00:00:00 2001 From: Matt McCormick Date: Tue, 20 Sep 2016 17:50:13 -0400 Subject: [PATCH] BUG: Address memory leak in GetImageFromArray Test based off suggestion from Roy Harnish in http://public.kitware.com/pipermail/insight-users/2016-September/053788.html --- include/itkPyBuffer.hxx | 2 + test/CMakeLists.txt | 7 +++- test/itkPyBufferMemoryLeakTest.py | 63 +++++++++++++++++++++++++++++++ 3 files changed, 70 insertions(+), 2 deletions(-) create mode 100644 test/itkPyBufferMemoryLeakTest.py diff --git a/include/itkPyBuffer.hxx b/include/itkPyBuffer.hxx index 2f00585..c0ad7a6 100644 --- a/include/itkPyBuffer.hxx +++ b/include/itkPyBuffer.hxx @@ -153,6 +153,8 @@ PyBuffer OutputImagePointer output = importer->GetOutput(); output->DisconnectPipeline(); + PyBuffer_Release(&pyBuffer); + return output; } diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 413cc85..884088b 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -13,7 +13,10 @@ # COMMAND BridgeNumPyTestDriver itkPyBufferTest) message("+++++++++" ${CMAKE_CURRENT_SOURCE_DIR}) if(ITK_WRAP_PYTHON) - itk_python_add_test(NAME DicomSliceReadPythonTest + itk_python_add_test(NAME itkDicomSliceReadPythonTest COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/itkPyBufferTest.py - ) + ) + itk_python_add_test(NAME itkPyBufferMemoryLeakTest + COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/itkPyBufferMemoryLeakTest.py + ) endif() diff --git a/test/itkPyBufferMemoryLeakTest.py b/test/itkPyBufferMemoryLeakTest.py new file mode 100644 index 0000000..2f5c6e0 --- /dev/null +++ b/test/itkPyBufferMemoryLeakTest.py @@ -0,0 +1,63 @@ +#========================================================================== +# +# Copyright Insight Software Consortium +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0.txt +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +#==========================================================================*/ +import sys +try: + import numpy as np +except ImportError: + # We don't have numpy -- bail + sys.exit(0) +import itk +import resource + +ImageType = itk.Image[itk.F, 3] +converter = itk.PyBuffer[ImageType] + +# adding +1 to numpy created once +inputNumpyVolume = np.ones([100,100,100], dtype=np.float32) +n = 10 +M = [] +X = range(n) +for i in range(n): + inputNumpyVolume += 1 + inputVolume = converter.GetImageFromArray(inputNumpyVolume) + M.append(resource.getrusage(resource.RUSAGE_SELF).ru_maxrss) + +if M[5] - M[4] > 1000: + print('Memory leak!') + sys.exit(1) + +# creating new numpy volume each time +M = [] +X = [x + n for x in range(n)] +for i in range(n): + inputNumpyVolume = np.ones([100,100,100], dtype=np.float32) + inputVolume = converter.GetImageFromArray(inputNumpyVolume) + M.append(resource.getrusage(resource.RUSAGE_SELF).ru_maxrss) +if M[5] - M[4] > 1000: + print('Memory leak!') + sys.exit(1) + +# creating new numpy volume but not calling converter.GetImageFromArray(inputNumpyVolume) +M = [] +X = [x + 2*n for x in range(n)] +for i in range(n): + inputNumpyVolume = np.ones([100,100,100], dtype=np.float32) + M.append(resource.getrusage(resource.RUSAGE_SELF).ru_maxrss) +if M[5] - M[4] > 1000: + print('Memory leak!') + sys.exit(1)