usage of calllib, libpointer, and libstruct with DLL that returns memory

46 visualizzazioni (ultimi 30 giorni)
Dear Folks,
I have three design goals based on speed, thread safety, and Application developer protection. The proposed solution is to have the Application hold all the memory required by the Algorithm that it calls inside an Application for loop. So the Algorithm has API functions that return I/O memory structures that the Application will hold onto (and pass to the Algorithm in each successive call). When the Application is done, it calls Deallocate API functions to release that memory. We would like all Applications to use the API in the same way, if possible. This includes our Matlab testing platform.
Is it possible to use calllib() and libpointer() in a Matlab function if the DLL is returning memory for Matlab to attach to the libpointer object? The DLL has "Allocate" and "Deallocate" functions that handle memory management for the I/O to the main DLL API interface function. It seems that I can use calllib() and libpointer() to pass data back-n-forth, but when I go to release the memory, I get these conditions:
1. If I release the memory by calling Deallocate() functions and passing the libpointer object and then followup with a "clear" or "unloadlibrary()", Matlab crashes.
2. If I release the memory by not using the DLL's Deallocate functions, but instead just rely on Matlab's "clear", then I get a memory leak that quickly builds up one iteration after another.
Can anyone explain to me if there is a workaround to this besides making an intermediate wrapper Application? Note that we are returning memory via return statements, rather than through the argument list.
Best regards, Kris
  1 Commento
Kristoffer Walker
Kristoffer Walker il 18 Set 2015
Modificato: Guillaume il 18 Set 2015
Here is some code to help understand what I am asking:
% Allocate Input struct and assign values to it
function MatlabFunction = MatlabFunction(matlabstruct)
% Assume DLL loaded
t = calllib('DLL32', 'AllocateInput');
t.Value.waves = libpointer('doublePtr',matlabstruct.waves);
t.Value.range = libpointer('doublePtr',matlabstruct.range);
t.Value.timeStep = matlabstruct.timeStep;
% Allocate output struct
o = calllib('DLL32', 'AllocateOutput');
% Execute main function, passing t and returning o
errorCode = calllib('DLL32', 'MainFunction', t, o);
if (errorCode ~=0)
errordlg('Call failed', 'Return Code Status');
return;
end
% Set data type of returned struct members in libpointer
setdatatype(o.Value.s, 'doublePtr', o.Value.nS, 1);
setdatatype(o.Value.f, 'doublePtr', o.Value.nF, 1);
setdatatype(o.Value.map, 'doublePtr', o.Value.nS*o.Value.nF, 1);
% Clean up. Do not use DLL's Deallocate and subsequent clear in Matlab, as that causes crash
% calllib('DLL32', 'DeallocateInput', t);
% calllib('DLL32', 'DeallocateOutput', o);
clear t o; % This clears the libpointers, but does not release the memory allocated by DLL
unloadlibrary('DLL32');
return;

Accedi per commentare.

Risposta accettata

Philip Borghesani
Philip Borghesani il 18 Set 2015
Modificato: Philip Borghesani il 18 Set 2015
You should be able to do what you are trying to do but have a bug or design flaw.
It is best to keep all memory in a single structure owned by the same owner. This line: t.Value.waves = libpointer('doublePtr',matlabstruct.waves); places a MATLAB owned and managed memory object inside t that is owned and allocated by your DLL. You free t then clear it in MATLAB but MATLAB does not know it is deallocated and goes to free waves causing a crash.
Without seeing the definition of the structure (in c) you are returning and a bit more info on what is expected I may not be able to give a complete response but you could start by trying this sequence however I have doubts that you want to make the above pointer assignment to waves.
%correct order to free t given its construction that I have some doubts about.
t.Value.waves=[]; or = libpointer;
t.Value.range=[];
calllib('DLL32', 'DeallocateInput', t);
clear t;
  4 Commenti
Kristoffer Walker
Kristoffer Walker il 4 Ott 2015
Hi Phil. So I finally got back to this project. I was able to use the concept of this sequence:
t.Value.waves(1:iend) = matlabstruct.waves;
with the input data. However, after careful review, I am having leaking issues when deallocating. I can use the following sequence:
t.Value.range=[];
calllib('DLL32', 'DeallocateInput', t);
clear t;
To prevent crashes, but it is still leaking. Upon further probing, it appears that leaking only happens when I use the above with this statement:
setdatatype(t.Value.range, 'doublePtr', nRange, 1);
If I do not use setdatatype and just ignore it (and do not manipulate the values that were initialized in the C++ struct whose memory was passed back to Matlab), then when I execute deallocate commands like this:
calllib('DLL32', 'DeallocateInput', t);
they do indeed deallocate the memory. So something seems to happen when setdatatype is executed that blocks Matlab from releasing the memory, even when I use the
t.Value.range=[];
set of commands prior to calling the deallocate functions. I also tried, instead of =[], =libpointer(), but got the same results. Any other ideas? I know from memory profiling tests that there are no memory leaks in the C++ code. I also verified my observations by adding a new, large array of known size into one of the struct allocations (and its corresponding deallocation) in the DLL. And saw the allocation clearly in the Windows Task Manager, but no drop after the =[], deallocation, and clear statements.
Best regards, Kris
Philip Borghesani
Philip Borghesani il 5 Ott 2015
Modificato: Philip Borghesani il 5 Ott 2015
First thought is you should not need to set the data type of range. You should be able to simple reshape it. My second thought is to use new variable instead of working through the original structure:
range=t.Value.range;
reshape(range,nRange,1)
%access or modify range value without assigning to the entire value;
clear range % because range was a pointer modifications
%have been made to the original structure.
Search your code for assignments to t.Value.range if you assign to the naked member then the original pointer will be lost.
do this:
range(:)=newdata;
% or
t.Value.range(:)=newdata %write new data into existing ptr
not this
t.Value.range=newdata; %replace pointer with new pointer possibly causing leak
value=newdata;
To continue solving your leak I suggest a new question with a reduced code set that can be more easily comprehended.

Accedi per commentare.

Più risposte (1)

Kristoffer Walker
Kristoffer Walker il 18 Set 2015
Modificato: Kristoffer Walker il 18 Set 2015
Hello Peter,
Thank you very much for your reply. Your response has gotten me much closer to a solution.
I have used the =[] (also tried =libpointer and got same result as with =[]) before the calllib to do the deallocation. Doing this prevents the crash as you suggested. However, it leaks memory for 3 of the 4 structs. I have simplified the code in my description above; in reality, there are 4 structs (see below). One of the structs that is allocated (with memory returning to MATLAB) is:
w = calllib('DLL32', 'AllocateWork');
When I profile MATLAB's memory footprint just before this call and just after the Deallocate call, they match (no leak). This is a special struct in that I do not have to assign values to, or read values from, inside MATLAB; I just allocate the memory for MATLAB to own and pass it back to the DLL whenever needed. I know it is using the memory correctly inside the DLL.
However, with the input t struct, I assign values to it in MATLAB as mentioned above using libpointer. When I profile this, MATLAB's footprint steps up significantly after executing this:
t = calllib('DLL32', 'AllocateInput');
but does not release any of this memory after I follow the steps suggested above using =[] before the deallocate calls. Also, the "clear o p w t" command does not seem to affect the memory footprint at the granularity of that reported by task manager (maybe the 4 libpointers sum to under 1 kB in size).
In addition, two others structs:
p = calllib('DLL32', 'AllocateInput2'); % I assign values to this, but no pointers to arrays
o = calllib('DLL32', 'AllocateOutput'); % Values are assigned to this inside the DLL
also do not get released using these steps.
The struct definitions are extern C blocked like this:
typedef struct
{
int nTime;
int nRange;
double *waves;
double *range;
double timeStep;
} t; // Input struct
typedef struct
{
double parm1;
int parm2;
} p; // Input struct
typdef struct
{
double* out1;
int nOut1;
unsigned int* dummyPtr; // this is not used in Matlab (this dummyPtr is a placeholder for a callback function pointer)
} o; // Output struct
struct w; // Workspace struct (forward declared with definition in a private *.h file that Matlab cannot see)
// Example allocation function prototype
t * AllocateInput(int nTime, int nRange);
I thought maybe the dummyPtr was causing a problem somehow, but I removed the o struct from the source code and I still have the same leaking issue. I also thought maybe the forward declaration of work was an issue, but I removed work from the MATLAB wrapper and still had the same problem with t, p, and o.
Best regards, Kris

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!

Translated by