I would like to create project with enabled Visual Studio memory leak detector (Memory Leak Detector)
It always worked fine and I could easily find memory leaks by running bunch of tests on my application and then checking the report.
But after statically linking OpenCV 3.0 to my project I got some false positives.
For instance the most frustrating error comes from StereoBMImpl::compute
method and call: ocl::useOpenCL()
After debugging I found the source of the "leak":
TLSData<CoreTLSData>& getCoreTlsData()
{
static TLSData<CoreTLSData> *value = new TLSData<CoreTLSData>();
return *value;
}
After analyzing this code we know the static object is allocated only once and everything should be OK. But now I have bunch of false positive memory leak reports like:
{1370349} normal block at 0x0E74D560, 24 bytes long.
Data: < > FF FF FF FF 00 00 00 00 00 00 00 00 00 00 00 00
{1370348} normal block at 0x0E74D4E0, 64 bytes long.
Data: <` t > 60 D5 74 0E CD CD CD CD CD CD CD CD CD CD CD CD
And now it's very difficult to find some real memory leaks in my application because there is set of false positives from OpenCV. I can't also run automatic memory leak tests because the output always contains some leaks.
Is there any way to remove these "pseudo" errors (if possible without changing OpenCV source code) ? It's very annoying.
I suppose other memory leaks detectors will also report some similar pseudo leaks because the new
operator is executed without delete
(object is automatically cleaned up by the OS).
I solved the problem in a quite dirty way, but I didn't find better. The solution requires modifying one OpenCV file (system.cpp). If you found a better way to fix it, please leave a comment. I suppose more people might have similar problems.
First I tried to solve the problem using @JamesMcNellis solution (from comment above), by explicitly mark the block as _IGNORE_BLOCK: new (_IGNORE_BLOCK, __FILE__, __LINE__)
. It was really good start to solve this problem. Unfortunately the leak class contains members like e.g. std::vector
, so tracing the allocations from this vector weren't suspended.
I started to read MSDN documentation to functions from crtdbg.h
and I found a way to suspend memory leaks checking for a while. It's possible by clearing the flag '_CRTDBG_ALLOC_MEM_DF' using function: _CrtSetDbgFlag
. Check details with example on MSDN: _CrtSetDbgFlag documentation.
This solution has probably one drawback (one I know), It suspends memory leaks checking for all threads.
Finally using RAII and few macro definitions I created simple class to manage this functionality.
All the changes I applied to official 3.0 source codes.
Somewhere on top (after precomp.hpp include) of system.cpp
file from OpenCV I added simple machinery:
#if defined(_MSC_VER) && defined(_DEBUG)
#include <crtdbg.h>
class MEMORY_LEAKS_CHECKING_SUSPENDER
{
public:
MEMORY_LEAKS_CHECKING_SUSPENDER()
{
value = _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG);
int new_flag = value & (~_CRTDBG_ALLOC_MEM_DF);
_CrtSetDbgFlag(new_flag);
}
~MEMORY_LEAKS_CHECKING_SUSPENDER()
{
_CrtSetDbgFlag(value);
}
private:
int value;
};
#define SUSPEND_MEMORY_LEAKS_CHECKING MEMORY_LEAKS_CHECKING_SUSPENDER suspend_memory_leaks_checking
#else
#define SUSPEND_MEMORY_LEAKS_CHECKING
#endif
And each time I want to suspend memory leaks checking i have to add: PAUSE_MEMORY_LEAKS_CHECKING;
It is enabled only in Visual Studio Debug compilation. The memory leaks tracing is automatically enabled after leaving the scope (destructor of MEMORY_LEAKS_CHECKING_SUSPENDER
class).
Currently to suspend my OpenCV memory leaks I added suspending allocations in functions:
getTLSContainerStorage()
void* TLSDataContainer::getData() const
TLSData<CoreTLSData>& getCoreTlsData()
inline TLSStorage* TLSStorage::get()
(The last suspension in TLSStorage is probably fixed on master OpenCV repository - I briefly checked the repository)
Each modification is very simple (e.g. for first leak):
Before modification:
static TLSContainerStorage& getTLSContainerStorage()
{
static TLSContainerStorage *tlsContainerStorage = new TLSContainerStorage();
return *tlsContainerStorage;
}
After modification:
static TLSContainerStorage& getTLSContainerStorage()
{
SUSPEND_MEMORY_LEAKS_CHECKING;
static TLSContainerStorage *tlsContainerStorage = new TLSContainerStorage();
return *tlsContainerStorage;
}
If you modify all these statements and still observe memory leaks and you use OpenCV as separately loaded dll then make sure you properly unloaded this dll using FreeLibrary
function. For the reason check DLLMain
function in OpenCV system.cpp
file and cv::__termination
variable usage.
I had the same problem in my project: statical build - MFC & OpenCV. Those solutions didn't help me. I tested them with OpenCV versions: 3.4.3 and 4.0.1. The issue went out when all opencv functions were into their own dlls. So my project configuration can be the following: MFC build - static, OpenCV - dynamic
Ok, I have an alternative workaround:
Make a special function, say, prefetchOpenCvMemoryLeaks()
, which creates/destroys a small matrix, creates/destroys a small window, and so on, so that OpenCV
leaks are saturated.
In the outer main()
function, save heap state with _CrtMemCheckpoint()
, call the entire project, at the end save heap state again and compare it with the old one by _CrtMemDifference()
.
This way you can check your own memory leaks regardless of OpenCV
ones.