[SOLVED] Leak issue using QtConcurrent
I have a memory leak in my application and it's very likely it's something about QtConcurrent::run on Windows7.
To be specific it's a 32 bits application developped under Visual C++ 2010 on Windows 7 Ultimate 64 bits.
I'm using QtConcurrent::run on several portions of the code. As this operation should be repeated billions of times this small leak is a real issue for me. I ve been working first with Qt 4.8.0 then with a patched version of 4.8.4 integrating the patch #38825 (https://codereview.qt-project.org/#change,38825) that fixes a bug with QtPrivate::ResultStore<T>::addResult. Note that I had to compile by myself as it is not binary compatible with 4.8.x.
Here is a simplified version of the code I'm using:
@class ProcessorModel : public Object
void doProcessing(unsigned int channel,cimg_library::CImg<uchar>& image, QDateTime dt);
// In the constructor
// In processing call
void ProcessorModel::doProcessing(unsigned int channel,cimg_library::CImg<uchar>& image, QDateTime dt)
if(!mutex.tryLock()) return; // Ignore processin
dataProcessorWatcher.setFuture(QtConcurrent::run(dataProcessor, &DataProcessor::processData, channel, image, dt));
I have run my application with Visual Leak Detector and the recurring leak errors like the following:
@---------- Block 771 at 0x049C3138: 4 bytes ----------
d:\Dev\DataProcessor\outputmanager.cpp (121): DataProcessord.exe!OutputManager::processResultWithAllOutputs + 0x7 bytes
d:\Dev\DataProcessor\DataProcessor.cpp (97): DataProcessord.exe!DataProcessor::processData
c:\qt\4.8.4patched\src\corelib\concurrent\qtconcurrentstoredfunctioncall.h (802): DataProcessord.exe!QtConcurrent::StoredMemberFunctionPointerCall3<bool,DataProcessor,unsigned int,unsigned int,cimg_library::CImg<unsigned char> &,cimg_library::CImg<unsigned char>,QDateTime,QDateTime>::runFunctor + 0x32 bytes
c:\qt\4.8.4patched\src\corelib\concurrent\qtconcurrentrunbase.h (106): DataProcessord.exe!QtConcurrent::RunFunctionTask<bool>::run + 0x11 bytes
c:\qt\4.8.4patched\src\corelib\concurrent\qthreadpool.cpp (107): QtCored4.dll!QThreadPoolThread::run + 0xC bytes
c:\qt\4.8.4patched\src\corelib\thread\qthread_win.cpp (348): QtCored4.dll!QThreadPrivate::start
0x5ABDA293 (File and line number not available): MSVCR100D.dll!beginthreadex + 0x243 bytes
0x5ABDA224 (File and line number not available): MSVCR100D.dll!beginthreadex + 0x1D4 bytes
0x75DB3677 (File and line number not available): kernel32.dll!BaseThreadInitThunk + 0x12 bytes
0x777C9F42 (File and line number not available): ntdll.dll!RtlInitializeExceptionChain + 0x63 bytes
0x777C9F15 (File and line number not available): ntdll.dll!RtlInitializeExceptionChain + 0x36 bytes
00 F9 00 0D ........ ........
I have searched on the internet but didn't find anything mentioning specifically my problem.
Do I do something wrong ? Can it be a leak in QtConcurrent ?
Thanks in advance
The VLD call stack indicates the problem is at:
What is in that line?
This line matches QMutex mutex = new QMutex();
Here is the complete code of this section (the definition is QHash<unsigned int,QMutex> mutexList):
@ QMutex *mutex = new QMutex();
So maybe it the mutex that has problem but it's not created often so itshouldn't explain my leak. Anyway I'd rather have a QHash<unsigned int,QMutex> mutexList but it doesn't seem possible.
So you create a QMutex on the heap at that line. And below you insert the pointer to the new Mutex object into some list. But are you 100% sure you will properly delete those Mutexes you stored in the list at a later time ???
If not, there you have your leak ;-)
Also: It's quite clear why you cannot have a list of QMutex (by value), only a list of QMutex* (by pointer). The former would store a copy of the QMutex by calling the copy constructor, i.e. it would effectively create a new separate Mutex instance, which certainly is not what we want. The latter stores a pointer to one and the same Mutex object, exactly as needed. Thus the copy constructor of QMutex is disabled for good reason!
Thanks for the confirmation for the QMutex: that's what I was thinking but I was not sure it was the best way to do it.
Actually the new QMutex was the problem. The code was supposed to go through this condition only once per channel but it was apparently not the case. I've added some control before creating a new QMutex and the leak has disappeared. Thanks for stressing what should have been obvious to me.