[Insight-users] memory leak check in ITK?
Luis Ibanez
luis . ibanez at kitware . com
Fri, 26 Sep 2003 18:43:37 -0400
Hi Feng,
Thanks for running Valgrind with the new option.
The suspicious place on the code is the process
for taking the output of the resample image filter.
In particular, the following section of the code:
>
> outputImage = resampleFilter->GetOutput();
> if(outputMemCopyOption == OUTPUT_MEM_BORROW){
> outputImage->GetPixelContainer()->SetContainerManageMemory(false);//non-copy
> *outBuffer = outputImage->GetPixelContainer()->GetImportPointer();
> }
> else
> memcpy((TPixel *)(*outBuffer),
> outputImage->GetPixelContainer()->GetBufferPointer(),
> outputVoxNum*sizeof(TPixel));
>
Question: What is the value of OUTPUT_MEM_BORROW ?
It seems that the resample image filter itself is not being destroyed
at the end of the scope of the function. It maybe that the parameter
"false" in
outputImage->GetPixelContainer()->SetContainerManageMemory(false);
is preventing the output image from being destroyed, and therefore
preventing its source filter from being destroyed.
Could you please comment out the section of code indicated above
and rerun Valgrind. (note that this time you shouldn't use the
"outBuffer" after this function returns, because it will be undefined.
Please let us know what you find,
Thanks
Luis
----------------------
Feng Ma wrote:
> Hi, Luis:
>
> I got the results. One of them is related to the affine transform for
> resample image filter. I posted the valgrind results and my code here:
>
> Valgrind reports:
>
> ==25148== Memcheck, a.k.a. Valgrind, a memory error detector for x86-linux.
> ==25148== Copyright (C) 2002-2003, and GNU GPL'd, by Julian Seward.
> ==25148== Using valgrind-20030725, a program supervision framework for
> x86-linux.
> ==25148== Copyright (C) 2000-2003, and GNU GPL'd, by Julian Seward.
> ==25148== Startup, with flags:
> ==25148== --suppressions=/usr/local/lib/valgrind/default.supp
> ==25148== --error-limit=no
> ==25148== --leak-check=yes
> ==25148== -v
> ==25148== --show-reachable=yes
> ==25148== --num-callers=50
> ==25148== Reading syms from /r2net/r2/fma/ITKTest/test/bin/fmatest
> ==25148== Reading syms from /lib/ld-2.2.4.so
> ==25148== Reading syms from /usr/local/lib/valgrind/vgskin_memcheck.so
> ==25148== Reading syms from /usr/local/lib/valgrind/valgrind.so
> ==25148== Reading syms from /usr/local/lib/valgrind/libpthread.so
> ==25148== Reading syms from /lib/libdl-2.2.4.so
> ==25148== Reading syms from /lib/i686/libm-2.2.4.so
> ==25148== Reading syms from /usr/local/lib/libstdc++.so.5.0.5
> ==25148== Reading syms from /usr/local/lib/libgcc_s.so.1
> ==25148== Reading syms from /lib/i686/libc-2.2.4.so
> ==25148== Reading suppressions file: /usr/local/lib/valgrind/default.supp
> ==25148== Estimated CPU clock rate is 997 MHz
> ==25148==
> Input volume: size (512 512 304) spacing (1.00 1.00 1.00) origin (0.00
> 0.00 0.00)
> ==25148== Warning: set address range perms: large range 159383552, a 0, v 0
> Output volume: size (64 64 38) spacing (8.00 8.00 8.00) origin (0.00
> 0.00 0.00)
> Resample successful
> Watershed successful
> ==25148== Warning: set address range perms: large range 159383552, a 1, v 1
> ==25148==
> ==25148== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 78 from 2)
> --25148--
> --25148-- supp: 40 __pthread_mutex_unlock/_IO_funlockfile
> --25148-- supp: 38
> pthread_error/__pthread_mutex_destroy/_IO_default_finish
> ==25148== malloc/free: in use at exit: 11304 bytes in 14 blocks.
> ==25148== malloc/free: 2182 allocs, 2168 frees, 169816622 bytes allocated.
> ==25148==
> ==25148== searching for pointers to 14 not-freed blocks.
> ==25148== checked 6202344 bytes.
> ==25148==
> ==25148== 16 bytes in 1 blocks are definitely lost in loss record 1 of 5
> ==25148== at 0x4002C90D: malloc (vg_replace_malloc.c:153)
> ==25148== by 0x4002CE92: realloc (vg_replace_malloc.c:291)
> ==25148== by 0x403F5064: __argz_append (argz-append.c:30)
> ==25148== by 0x403923D6: __newlocale (newlocale.c:100)
> ==25148== by 0x402F59AD:
> std::locale::facet::_S_create_c_locale(__locale_struct*&, char const*,
> __locale_struct*) (c++locale.cc:171)
> ==25148== by 0x402ED139:
> std::locale::_Impl::_Impl(std::locale::facet**, unsigned, bool)
> (../../../../gcc-3.3.1/libstdc++-v3/src/localename.cc:226)
> ==25148== by 0x402EA0E4: std::locale::classic()
> (../../../../gcc-3.3.1/libstdc++-v3/libsupc++/new:92)
> ==25148== by 0x402E8BAC: std::locale::locale()
> (/r2/fma/gcc331Build/i686-pc-linux-gnu/libstdc++-v3/include/bits/locale_classes.h:179)
>
> ==25148== by 0x402FC636: std::basic_filebuf<char,
> std::char_traits<char> >::basic_filebuf()
> (/r2/fma/gcc331Build/i686-pc-linux-gnu/libstdc++-v3/include/streambuf:583)
> ==25148== by 0x402FBAA1: __gnu_cxx::stdio_filebuf<char,
> std::char_traits<char> >::stdio_filebuf(_IO_FILE*, std::_Ios_Openmode,
> unsigned)
> (/r2/fma/gcc331Build/i686-pc-linux-gnu/libstdc++-v3/include/ext/stdio_filebuf.h:147)
>
> ==25148== by 0x402E7DCF: std::ios_base::Init::_S_ios_create(bool)
> (../../../../gcc-3.3.1/libstdc++-v3/libsupc++/new:92)
> ==25148== by 0x402E8464: std::ios_base::Init::Init()
> (../../../../gcc-3.3.1/libstdc++-v3/src/ios.cc:228)
> ==25148== by 0x402E7B76:
> __static_initialization_and_destruction_0(int, int)
> (/r2/fma/gcc331Build/i686-pc-linux-gnu/libstdc++-v3/include/iostream:77)
> ==25148== by 0x402E7B99:
> _GLOBAL__I__ZThn8_NSt14basic_iostreamIwSt11char_traitsIwEED0Ev.._.._.._.._gcc_3.3.1_libstdc___v3_src_io_inst.ccl5ZUua
> (/r2/fma/gcc331Build/i686-pc-linux-gnu/libstdc++-v3/include/bits/locale_facets.h:210)
>
> ==25148== by 0x402E5B84: (within /usr/local/lib/libstdc++.so.5.0.5)
> ==25148== by 0x402DE83D: (within /usr/local/lib/libstdc++.so.5.0.5)
> ==25148== by 0x4000DAA6: _dl_init (dl-init.c:70)
> ==25148== by 0x40001ED0: (within /lib/ld-2.2.4.so)
> ==25148==
> ==25148==
> ==25148== 24 bytes in 2 blocks are definitely lost in loss record 2 of 5
> ==25148== at 0x4002CB02: __builtin_vec_new (vg_replace_malloc.c:197)
> ==25148== by 0x4002CB6D: operator new[](unsigned)
> (vg_replace_malloc.c:210)
> ==25148== by 0x8158A56: vnl_c_vector_alloc(int, int)
> (/space2/Devel/InsightToolkit-1.4.0/Utilities/vxl/vnl/vnl_c_vector.txx:362)
> ==25148== by 0x815892C: vnl_c_vector<double>::allocate_Tptr(int)
> (/space2/Devel/InsightToolkit-1.4.0/Utilities/vxl/vnl/vnl_c_vector.txx:383)
> ==25148== by 0x80E97D4:
> vnl_matrix_ref<double>::vnl_matrix_ref(unsigned, unsigned, double*)
> (/space2/Devel/InsightToolkit-1.4.0/Utilities/vxl/vnl/vnl_matrix_ref.h:46)
> ==25148== by 0x80E979E: vnl_matrix_fixed<double, 3, 3>::operator
> vnl_matrix_ref<double> const() const
> (/r2/fma/ITK/1.4/Debug/include/InsightToolkit/Utilities/vxl/vnl/vnl_matrix_fixed.h:533)
>
> ==25148== by 0x80E9655: itk::Matrix<double, 3, 3>::GetInverse() const
> (/r2/fma/ITK/1.4/Debug/include/InsightToolkit/Common/itkMatrix.txx:204)
> ==25148== by 0x80E7E36: itk::AffineTransform<double,
> 3>::RecomputeInverse()
> (/r2/fma/ITK/1.4/Debug/include/InsightToolkit/Common/itkAffineTransform.txx:591)
>
> ==25148== by 0x80E7450: itk::AffineTransform<double,
> 3>::SetIdentity()
> (/r2/fma/ITK/1.4/Debug/include/InsightToolkit/Common/itkAffineTransform.h:193)
>
> ==25148== by 0x80E6B14: int itkResampleDataBuffer<short, 3>(short*,
> int (&) [3], int, int, int*, double*, double*, short**, int*, double*,
> double*, int) (/r2net/r2/fma/ITKTest/ITKWrapLib/src/itkResample.cxx:42)
> ==25148== by 0x80D55DC: itkResample3DShortDataBufferInC
> (/r2net/r2/fma/ITKTest/ITKWrapLib/src/itkResample.cxx:125)
> ==25148== by 0x80D52C4: cmain (/r2net/r2/fma/ITKTest/test/src/test.c:82)
> ==25148== by 0x80D4ED4: main (/r2net/r2/fma/ITKTest/test/src/main.cpp:4)
> ==25148== by 0x40387656: __libc_start_main
> (../sysdeps/generic/libc-start.c:129)
> ==25148== by 0x80D4DC0: (within /r2net/r2/fma/ITKTest/test/bin/fmatest)
> ==25148==
> ==25148==
> ==25148== 64 bytes in 1 blocks are still reachable in loss record 3 of 5
> ==25148== at 0x4002C90D: malloc (vg_replace_malloc.c:153)
> ==25148== by 0x403926BC: __newlocale (newlocale.c:162)
> ==25148== by 0x402F59AD:
> std::locale::facet::_S_create_c_locale(__locale_struct*&, char const*,
> __locale_struct*) (c++locale.cc:171)
> ==25148== by 0x402ED139:
> std::locale::_Impl::_Impl(std::locale::facet**, unsigned, bool)
> (../../../../gcc-3.3.1/libstdc++-v3/src/localename.cc:226)
> ==25148== by 0x402EA0E4: std::locale::classic()
> (../../../../gcc-3.3.1/libstdc++-v3/libsupc++/new:92)
> ==25148== by 0x402E8BAC: std::locale::locale()
> (/r2/fma/gcc331Build/i686-pc-linux-gnu/libstdc++-v3/include/bits/locale_classes.h:179)
>
> ==25148== by 0x402FC636: std::basic_filebuf<char,
> std::char_traits<char> >::basic_filebuf()
> (/r2/fma/gcc331Build/i686-pc-linux-gnu/libstdc++-v3/include/streambuf:583)
> ==25148== by 0x402FBAA1: __gnu_cxx::stdio_filebuf<char,
> std::char_traits<char> >::stdio_filebuf(_IO_FILE*, std::_Ios_Openmode,
> unsigned)
> (/r2/fma/gcc331Build/i686-pc-linux-gnu/libstdc++-v3/include/ext/stdio_filebuf.h:147)
>
> ==25148== by 0x402E7DCF: std::ios_base::Init::_S_ios_create(bool)
> (../../../../gcc-3.3.1/libstdc++-v3/libsupc++/new:92)
> ==25148== by 0x402E8464: std::ios_base::Init::Init()
> (../../../../gcc-3.3.1/libstdc++-v3/src/ios.cc:228)
> ==25148== by 0x402E7B76:
> __static_initialization_and_destruction_0(int, int)
> (/r2/fma/gcc331Build/i686-pc-linux-gnu/libstdc++-v3/include/iostream:77)
> ==25148== by 0x402E7B99:
> _GLOBAL__I__ZThn8_NSt14basic_iostreamIwSt11char_traitsIwEED0Ev.._.._.._.._gcc_3.3.1_libstdc___v3_src_io_inst.ccl5ZUua
> (/r2/fma/gcc331Build/i686-pc-linux-gnu/libstdc++-v3/include/bits/locale_facets.h:210)
>
> ==25148== by 0x402E5B84: (within /usr/local/lib/libstdc++.so.5.0.5)
> ==25148== by 0x402DE83D: (within /usr/local/lib/libstdc++.so.5.0.5)
> ==25148== by 0x4000DAA6: _dl_init (dl-init.c:70)
> ==25148== by 0x40001ED0: (within /lib/ld-2.2.4.so)
> ==25148==
> ==25148==
> ==25148== 11000 bytes in 9 blocks are still reachable in loss record 5 of 5
> ==25148== at 0x4002C9FD: __builtin_new (vg_replace_malloc.c:172)
> ==25148== by 0x4002CA68: operator new(unsigned)
> (vg_replace_malloc.c:185)
> ==25148== by 0x40332B2A: std::__default_alloc_template<true,
> 0>::_S_chunk_alloc(unsigned, int&)
> (/r2/fma/gcc331Build/i686-pc-linux-gnu/libstdc++-v3/include/bits/stl_alloc.h:108)
>
> ==25148== by 0x40332A3C: std::__default_alloc_template<true,
> 0>::_S_refill(unsigned)
> (/r2/fma/gcc331Build/i686-pc-linux-gnu/libstdc++-v3/include/bits/stl_alloc.h:550)
>
> ==25148== by 0x40332737: std::__default_alloc_template<true,
> 0>::allocate(unsigned)
> (/r2/fma/gcc331Build/i686-pc-linux-gnu/libstdc++-v3/include/bits/stl_alloc.h:357)
>
> ==25148== by 0x8141BA6:
> std::__simple_alloc<std::_List_node<itk::ObjectFactoryBase*>,
> std::__default_alloc_template<true, 0> >::allocate(unsigned)
> (/usr/local/include/c++/3.3.1/bits/stl_alloc.h:232)
> ==25148== by 0x8141B79:
> std::_List_alloc_base<itk::ObjectFactoryBase*,
> std::allocator<itk::ObjectFactoryBase*>, true>::_M_get_node()
> (/usr/local/include/c++/3.3.1/bits/stl_list.h:275)
> ==25148== by 0x8141B40: std::_List_base<itk::ObjectFactoryBase*,
> std::allocator<itk::ObjectFactoryBase*>
> >::_List_base(std::allocator<itk::ObjectFactoryBase*> const&)
> (/usr/local/include/c++/3.3.1/bits/stl_list.h:304)
> ==25148== by 0x8140F9B: std::list<itk::ObjectFactoryBase*,
> std::allocator<itk::ObjectFactoryBase*>
> >::list(std::allocator<itk::ObjectFactoryBase*> const&)
> (/usr/local/include/c++/3.3.1/bits/stl_list.h:452)
> ==25148== by 0x80DC17E: itk::ObjectFactoryBase::Initialize()
> (/space2/Devel/InsightToolkit-1.4.0/Code/Common/itkObjectFactoryBase.cxx:171)
>
> ==25148== by 0x80DBEE0: itk::ObjectFactoryBase::CreateInstance(char
> const*)
> (/space2/Devel/InsightToolkit-1.4.0/Code/Common/itkObjectFactoryBase.cxx:115)
>
> ==25148== by 0x80E8919:
> itk::ObjectFactory<itk::ResampleImageFilter<itk::Image<short, 3>,
> itk::Image<short, 3> > >::Create()
> (/r2/fma/ITK/1.4/Debug/include/InsightToolkit/Common/itkObjectFactory.h:52)
> ==25148== by 0x80E87EE: itk::ResampleImageFilter<itk::Image<short,
> 3>, itk::Image<short, 3> >::New()
> (/r2/fma/ITK/1.4/Debug/include/InsightToolkit/BasicFilters/itkResampleImageFilter.h:77)
>
> ==25148== by 0x80E6AD4: int itkResampleDataBuffer<short, 3>(short*,
> int (&) [3], int, int, int*, double*, double*, short**, int*, double*,
> double*, int) (/r2net/r2/fma/ITKTest/ITKWrapLib/src/itkResample.cxx:29)
> ==25148== by 0x80D55DC: itkResample3DShortDataBufferInC
> (/r2net/r2/fma/ITKTest/ITKWrapLib/src/itkResample.cxx:125)
> ==25148== by 0x80D52C4: cmain (/r2net/r2/fma/ITKTest/test/src/test.c:82)
> ==25148== by 0x80D4ED4: main (/r2net/r2/fma/ITKTest/test/src/main.cpp:4)
> ==25148== by 0x40387656: __libc_start_main
> (../sysdeps/generic/libc-start.c:129)
> ==25148== by 0x80D4DC0: (within /r2net/r2/fma/ITKTest/test/bin/fmatest)
> ==25148==
> ==25148== LEAK SUMMARY:
> ==25148== definitely lost: 40 bytes in 3 blocks.
> ==25148== possibly lost: 0 bytes in 0 blocks.
> ==25148== still reachable: 11064 bytes in 10 blocks.
> ==25148== suppressed: 200 bytes in 1 blocks.
> ==25148==
> --25148-- TT/TC: 0 tc sectors discarded.
> --25148-- 11322 chainings, 0 unchainings.
> --25148-- translate: new 17176 (264522 -> 3542893; ratio 133:10)
> --25148-- discard 0 (0 -> 0; ratio 0:10).
> --25148-- dispatch: 9126900000 jumps (bb entries), of which 3183030992
> (34%) were unchained.
> --25148-- 182628/17242078 major/minor sched events. 17011469
> tt_fast misses.
> --25148-- reg-alloc: 3556 t-req-spill, 653228+18449 orig+spill uis,
> 85799 total-reg-r.
> --25148-- sanity: 182629 cheap, 7306 expensive checks.
> --25148-- ccalls: 87757 C calls, 59% saves+restores avoided (309252
> bytes)
> --25148-- 119583 args, avg 0.87 setup instrs each (30062 bytes)
> --25148-- 0% clear the stack (263271 bytes)
> --25148-- 28888 retvals, 30% of reg-reg movs avoided (16782
> bytes)
>
>
> My code: itkResample.cxx
>
> #include <fstream>
> #include <string>
> #include "itkCastImageFilter.h"
> #include "itkResampleImageFilter.h"
> #include "itkNearestNeighborInterpolateImageFunction.h"
> #include "itkLinearInterpolateImageFunction.h"
> #include "itkWrapCommon.h"
> #include "itkResample.h"
>
> extern "C" {
> #include <string.h>
> #include <stdio.h>
> }
>
> template <class TPixel, unsigned int VImageDimension>
> int itkResampleDataBuffer(TPixel *inBuffer, int
> (&zoomOut)[VImageDimension],
> int interpolateType, int defaultVoxelValue,
> int *inSize, double *inSpacing, double *inOrigin,
> TPixel **outBuffer, int *outSize,
> double *outSpacing, double *outOrigin,
> int outputMemCopyOption)
> {
> // const int VImageDimension = dim;
> int i, inputVoxNum, outputVoxNum;
>
> typedef itk::Image<TPixel, VImageDimension> ImageType;
>
> typedef itk::ResampleImageFilter<ImageType, ImageType>
> ResampleFilterType;
> typename ResampleFilterType::Pointer resampleFilter =
> ResampleFilterType::New();
>
> typedef itk::NearestNeighborInterpolateImageFunction<
> ImageType, double > NNInterpolatorType;
> typename NNInterpolatorType::Pointer nearestNeighborInterpolator =
> NNInterpolatorType::New();
>
> typedef itk::LinearInterpolateImageFunction<
> ImageType, double > LinearInterpolatorType;
> typename LinearInterpolatorType::Pointer linearInterpolator =
> LinearInterpolatorType::New();
>
> typedef itk::AffineTransform<double, VImageDimension> TransformType;
> typename TransformType::Pointer transform = TransformType::New();
> transform->SetIdentity();
>
> resampleFilter->SetTransform(transform);
> if( interpolateType == RESAMPLE_INTERPOLATE_LINEAR)
> resampleFilter->SetInterpolator(linearInterpolator);
> else
> resampleFilter->SetInterpolator(nearestNeighborInterpolator);
>
> resampleFilter->SetDefaultPixelValue(defaultVoxelValue);
>
> typename ImageType::Pointer outputImage = NULL;
> typename ImageType::Pointer inputImage = ImageType::New();
> typename ImageType::RegionType inputRegion;
> typename ImageType::RegionType outputRegion;
> typename ImageType::RegionType::IndexType inputIndex;
> typename ImageType::RegionType::SizeType inputSize;
> typename ImageType::RegionType::SizeType outputSize;
>
> inputVoxNum = 1;
> outputVoxNum = 1;
> for(i = 0; i < VImageDimension; i ++){
> inputIndex[i] = 0;
> inputSize[i] = inSize[i];
> inputVoxNum *= inSize[i];
> outputSize[i] = outSize[i];
> outputVoxNum *= outSize[i];
> }
>
> inputRegion.SetIndex(inputIndex);
> inputRegion.SetSize(inputSize);
> inputImage->SetRegions(inputRegion);
> inputImage->SetSpacing(inSpacing);
> inputImage->SetOrigin(inOrigin);
>
> typename itk::ImportImageContainer<long unsigned int, TPixel>::Pointer
> importer;
> importer = itk::ImportImageContainer<long unsigned int, TPixel>::New();
> importer->Initialize();
> importer->SetImportPointer(inBuffer, inputVoxNum, false);
> inputImage->SetPixelContainer(importer);
>
> resampleFilter->SetOutputSpacing(outSpacing);
> resampleFilter->SetOutputOrigin(outOrigin);
> resampleFilter->SetSize(outputSize);
> resampleFilter->SetInput(inputImage);
> resampleFilter->Update();
>
> outputImage = resampleFilter->GetOutput();
> if(outputMemCopyOption == OUTPUT_MEM_BORROW){
> outputImage->GetPixelContainer()->SetContainerManageMemory(false);//non-copy
>
> *outBuffer = outputImage->GetPixelContainer()->GetImportPointer();
> }
> else
> memcpy((TPixel *)(*outBuffer),
> outputImage->GetPixelContainer()->GetBufferPointer(),
> outputVoxNum*sizeof(TPixel));
>
> return 0;
> }
>
>
> extern "C" int itkResample3DShortDataBufferInC(short *inBuffer, int
> *_zoomOut,
> int interpolateType,
> int defaultVoxelValue,
> int *inSize, double
> *inSpacing,
> double *inOrigin,
> short **outBuffer, int
> *outSize,
> double *outSpacing,
> double *outOrigin)
> {
> int zoomOut[3], i;
> //instantiation purpose
> for(i = 0; i < 3; i ++)
> zoomOut[i] = _zoomOut[i];
>
> if( *outBuffer == NULL)
> return 1; //C caller should allocate output memory first
>
> return(itkResampleDataBuffer(inBuffer, zoomOut, interpolateType,
> defaultVoxelValue,
> inSize, inSpacing, inOrigin, outBuffer,
> outSize, outSpacing, outOrigin,
> OUTPUT_MEM_COPY));
> }
>
>
> Thanks a lot.
>
> -Feng
>
>
>> From: Luis Ibanez <luis . ibanez at kitware . com>
>> To: Feng Ma <mafeng at hotmail . com>
>> CC: insight-users at itk . org
>> Subject: Re: [Insight-users] memory leak check in ITK?
>> Date: Fri, 26 Sep 2003 15:28:37 -0400
>>
>>
>> Hi Feng,
>>
>> Thanks for your report,
>>
>> There may still be a memory leak related to the use
>> of a vnl_c_vector. However the current Valgrind
>> report may not be sufficient to locate the source
>> of the leak.
>>
>> By default Valgrind reports only 4 levels of the callstack,
>>
>> Please run your test again, but this time using the option:
>>
>> valgrind --num-callers=50
>>
>> That will display at least 50 levels of the call stack.
>>
>> Hopefully the real source of the leak reported by vnl_c_vector
>> will show up in the new report.
>>
>>
>> Please let us know what you get,
>>
>>
>> Thanks
>>
>>
>>
>> Luis
>>
>>
>>
>
> _________________________________________________________________
> Instant message with integrated webcam using MSN Messenger 6.0. Try it
> now FREE! http://msnmessenger-download . com
>
>