2

I wrote a C++ interface dll to call some key image processing statistical measuring methods from Intel's Integrated Performance Primitives (IPP) library so we can exploit SIMD capabilities. I was able to pass two 2D Matlab arrays over into the function using calllib

A = single( rand(3,4) );
B = single( rand(3,2) );

pOut = calllib('IPPInterface', 'myFunc', A' , B' , size(A,1), size(A,2) , size(B,1), size(B,2) );

Where in C++ the myFunc has the following signature, and snippet of body...

float* myFunc( float A[] , float B[] , int nRowsA , int nColsA , int nRowsB , int nColsB )
{
    ...
    float[] pDst = new float[nRowsA*nColsA];
    ...
    return pDst;
}

What I'm unsure of is how and if Matlab successfully deletes such buffers from memory. They ultimately wind up in the Matlab process as lib.pointers:

>> class(pOut)

ans =

lib.pointer

I'm just curious if what I'm doing is a bad idea, or if calling Matlab's clear pOut would take care of everything and avoid the conceivable memory leak.

jxramos
  • 7,356
  • 6
  • 57
  • 105
  • 1
    It's worth noting that Matlab **can't** delete the memory for you, because there are dozens of native allocators, all mutually incompatible, and you didn't indicate to Matlab which one is being used. – Ben Voigt Jul 15 '15 at 20:25
  • @BenVoigt I'm unfamiliar with that notion of incompatible native allocators, are you speaking of across OS platforms or within a given OS? I know different means of allocation have different behaviors, like calloc, malloc, C++ new, but where does this notion of incompatibility fit into that picture if at all with the examples I'm thinking of. – jxramos Jul 15 '15 at 20:34
  • 1
    I'm exactly talking about `malloc` vs `new` vs `new[]` vs `HeapAlloc` vs `VirtualAlloc` vs `SysAllocString` vs `SafeArrayCreateVector` vs `CoTaskMemAlloc` vs .NET garbage collector. Then there's the fact that `new` provided by one compiler is not the same as provided by another compiler (which is why the OS provides a `HeapAlloc` -- so you can be independent of your compiler) and on top of that, C++ allows overloading `::operator new` so that it isn't even using the compiler-provided implementation. – Ben Voigt Jul 15 '15 at 20:59
  • 1
    And the pointer returned by an export might not even be dynamically allocated at all -- it could be a pointer into a memory-mapped file, or a global variable inside the DLL with static lifetime. Or it might be a pointer to a middle of a larger dynamic allocation. In the end, there is no possible way for Matlab to deallocate correctly, unless you somehow tell it which function to use. The best you could hope for is an ability to designate a deallocation function for Matlab to call when the Matlab object gets garbage collected. – Ben Voigt Jul 15 '15 at 21:00
  • @BenVoigt solid, this is the kind of thinking I have to begin to appreciate when cooking up all this multilanguage stuff I've been working on. These dynamic typed languages take care of a lot of details, but it's true that what I'm doing is so external from Matlab there's no way it would have a clue how to treat entities sent its way. I was assuming too much of Matlab, and now I know and can begin to ask similar questions when crossing other language barriers. Thanks a bunch. – jxramos Jul 15 '15 at 21:15
  • @BenVoigt I think I'm seeing where the notion of compatibility fits in here. It has to do with the fact that each form of allocation has an associated form of deallocation and in general two forms of allocation may not necessarily share the same means of deallocation. If they all did than Matlab could exploit that common form, but since that's not the case it cannot make such an assumption on the proper means of deallocation on your behalf. – jxramos Jul 15 '15 at 21:43

1 Answers1

2

So I've been doing some memory testing by creating in Matlab two arrays as follows...

I = single( rand( 1200 , 1600 ) );
T = single( rand( 100  , 100  ) );

I then put my function in a loop with a printing of memory usage to a text file and clearing the returned libpointer.

for i = 1:10000
    lp = calllib('IPPInterface', 'myFunc', I , T , size(I,2) , size(I,1) , size(T,2) , size(T,1) );
    clear lp;

    [u,s] = memory;

    fprintf( fileID ,'%13g    %13s\n' ,  u.MemUsedMATLAB , s.SystemMemory.Available );
end 

Going that route definitely fills up my physical memory as you can see below, and has convinced me that what I was doing was a bad idea and Matlab does not handle this in some automated garbage collection like fashion for you.

>> memory
Maximum possible array:              38799 MB (4.068e+010 bytes) *
Memory available for all arrays:     38799 MB (4.068e+010 bytes) *
Memory used by MATLAB:               21393 MB (2.243e+010 bytes)
Physical Memory (RAM):               34814 MB (3.650e+010 bytes)

*  Limited by System Memory (physical + swap file) available.
>> clear all
>> memory
Maximum possible array:              38803 MB (4.069e+010 bytes) *
Memory available for all arrays:     38803 MB (4.069e+010 bytes) *
Memory used by MATLAB:               21388 MB (2.243e+010 bytes)
Physical Memory (RAM):               34814 MB (3.650e+010 bytes)

*  Limited by System Memory (physical + swap file) available.
>> 

Matlab memory profile log data

Task Manager showing memory leak

If I close Matlab than the OS naturally reclaims all that memory.

Task Manager showing reclaimed memory as Matlab is closed

After digging around Matlab's website I did find a close enough example whereby the example had dynamically allocated a c-struct in a shared library, and where later on Matlab had to call a function written in that same library whose sole task was to delete that struct.

Working with Pointer Arguments; Multilevel Pointers

This example is right on, after implementing a simple interface call to the shared lib to deallocate my array and using it after I was done

void deallocateArray( float* A )
{
    delete[] A;
}

The memory profile is flat, and the entire 10000 iterations complete much more rapidly...

for i = 1:10000
    lp = calllib('IPPInterface', 'myFunc', I , T , size(I,2) , size(I,1) , size(T,2) , size(T,1) );
    calllib('IPPInterface', 'deallocateArray', lp );
    clear lp;

    [u,s] = memory;

    fprintf( fileID ,'%13g    %13s\n' ,  u.MemUsedMATLAB , s.SystemMemory.Available );
end 

enter image description here

jxramos
  • 7,356
  • 6
  • 57
  • 105