Forum Discussion
about XLL memory management
Rodrigo_ Thanks for reply. I know the static approach and I believe there is a typo in your example, xlbitDLLFree is wrong, which will direct Excel to free (by call back into xlAutoFree12) a static allocated memory. The right one should be.
__declspec(dllexport)
LPXLOPER12 test() {
static XLOPER12 ret = { xltypeInt, { 10 } };
return &ret;
}What I'm curious is how the xlFree (in xlAutoFree12) know whether an LPXLOPER12 is returned by a thread-safe UDF or by a non thread-safe UDF.
Just few minutes ago, I implemented my free logic as follow
void myxlFree(LPXLOPER12 px) {
if (px->xltype == xltypeStr) {
if (px->val.str) {
delete px->val.str;
px->val.str = nullptr;
}
} else if (px->xltype == xltypeRef ) {
if(px->val.mref.lpmref) {
delete px->val.mref.lpmref;
px->val.mref.lpmref = nullptr;
}
} else if (px->xltype == xltypeMulti) {
if (px->val.array.lparray) {
auto count = px->val.array.rows*px->val.array.columns;
for(unsigned i=0; i < count; i++) {
myxlFree(&px->val.array.lparray[i]);
}
delete px->val.array.lparray;
px->val.array.lparray = nullptr;
}
}
}and replace following line
__declspec(dllexport)
void WINAPI xlAutoFree12(LPXLOPER12 pxFree) {
Excel12(xlFree,nullptr,1,pxFree);
delete pxFree;
}with
__declspec(dllexport)
void WINAPI xlAutoFree12(LPXLOPER12 pxFree) {
myxlFree(pxFree);
delete pxFree;
}test just works so far. But I'm not sure if there are potential issues.
You are correct about the typo in my previous response. Thank you for pointing that out.
Regarding your question about how xlFree in xlAutoFree12 knows whether an LPXLOPER12 is returned by a thread-safe UDF or a non thread-safe UDF, the answer is that it doesn't.
When xlFree is called, it simply deallocates the memory pointed to by the LPXLOPER12. It is up to the UDF to make sure that it only calls xlFree on memory that was allocated using xl* functions like xlCoerce, xlret, xlAsyncReturn, and xlSet. If the UDF allocated memory using any other means, it must handle the deallocation itself.
In your implementation of myxlFree, you are correctly freeing the memory based on the xltype of the LPXLOPER12. This is a good practice to ensure that the memory is freed correctly for each type of data. Your implementation should work fine as long as you only call it on memory that was allocated using xl* functions.
- yushangMar 29, 2023Brass Contributor
Rodrigo_ Thanks for reply. I would like to summarize the usage of xlbitDLLFree as follow
1. xlbitDLLFree is used only in scenario when UDF return a dynamic allocated XLOPER12
2. For the returned XLOPER12, if xlbitDLLFree is set, Excel will pass it back to xlAutoFree12. if not set there will be a memory leak.
there leaves a question, what will happen if XLL did not export xlAutoFree12?
In parallel, can I summarize the usage of xlbitXLFree as follow?
1. xlbitXLFree is used only in scenario when UDF return a dynamic allocated XLOPER12
2. For the returned XLOPER12, if xlbitXLFree is set, Excel will free it including the XLOPER12 itself (I'm especially caring about this, from the official https://learn.microsoft.com/en-us/office/client-developer/excel/memory-management-in-excel#example, it seems there is little chance I'm right), if not set, there will be a memory leak.
(all the dynamic allocated XLOPER12 mentioned above does not contain static allocated memory, for example, val.str is not static allocated).
- yushangMar 31, 2023Brass Contributor
yushang I'm overthinking. And I would like to summarize the memory bits as follow, memory bits is only used when UDF returning the address of XLOPER12
memory bits vs XLOPER12 static allocated dynamic allocated xlbitDLLFree Fail. Excel will pass back the static allocated XLOPER12 to xlAutoFree12
Ok. Excel will pass back the XLOPER12 to xlAutoFree12 xlbitXLFree Ok. Excel will free dynamic allocated memories in the XLOPER12 (whether they are allocated by Excel or UDF, it makes no difference). XLOPER12 itself will be freed when XLL is unloaded. Leak. Excel will work as descripted in the left column. But it will not pass back the XLOPER12. - lori_mMar 29, 2023Iron Contributor
For writing high performance custom functions I'd recommend using a C++ wrapper to avoid memory management headaches. Options include,
XLL+: https://www.planatechsolutions.com/xllplus/
XLW: https://www.youtube.com/watch?v=k0V6nvWjMnI
Both provide a C++ interface for creating xlls (templates, smart pointers, etc.) the latter being open source.