Dans mon application (en cours de développement sous Windows 8 avec MySQL Connector/C++), je crée des instructions préparées et ne les supprime qu'à la fin de l'application. Mais pendant l'exécution de l'application, j'exécute les requêtes et ne supprime que les ensembles de résultats.Instructions préparées: La mémoire reste allouée au jeu de résultats malgré sa suppression
Cependant, j'ai observé beaucoup de mémoire reste encore alloué et je l'ai senti plus que prévu. J'examine avec Visual Leak Detector et à ma grande surprise j'ai trouvé des fuites qui ont été montrées dans le pointeur de l'ensemble des résultats malgré que je les supprimais correctement. J'ai donc écrit un programme de démonstration qui fait exactement cela. C'est créer une instruction préparée, créer une requête, récupérer le résultat, supprimer le résultat (mais ne pas supprimer l'instruction préparée à la fin afin que nous puissions voir les fuites) et quitter. Voici le code de démonstration MySQL.cpp
:
#include "stdafx.h"
#include <conio.h>
#define CPPCONN_LIB_BUILD // We must define this as we are linking mysql connector in static library. It directs build_config.h to not to put __declspec(dllimport) before function declarations.
#include <driver/mysql_connection.h>
#include <cppconn/driver.h>
#include <cppconn/exception.h>
#include <cppconn/resultset.h>
#include <cppconn/statement.h>
#include <cppconn/prepared_statement.h>
#include <vld.h> // Visual memory leak detector
int _tmain(int argc, _TCHAR* argv[])
{
sql::Connection *pConnection = NULL;
sql::ResultSet *pResultSet = NULL;
sql::PreparedStatement *pPreparedStatement = NULL;
sql::Driver *driver = NULL;
/* Create a connection */
driver = get_driver_instance();
pConnection = driver->connect("tcp://127.0.0.1:3306", "username", "password");
pConnection->setSchema("MYDB");
pConnection->setAutoCommit(0);
sql::ResultSet* pResultSet;
pPreparedStatement = pConnection->prepareStatement ("select * from mytable where mycolumn > ?"); // mytable has mycolumn that contains 1000 numbers starting from 1
pPreparedStatement->setInt(1, 1);
pResultSet= pPreparedStatement->executeQuery();
int count = pResultSet->rowsCount();
printf("\nTotal rows found %d", count);
delete pResultSet;
// delete pPreparedStatement; // Let's not delete prepared statement to see demo of memory leak in pResultSet
delete pConnection;
printf ("\nDone! Quitting...");
return 0;
}
Et voici rapport:
Visual Leak Detector Version 2.4RC2 installed.
Aggregating duplicate leaks.
Suppressing data dumps.
Outputting the report to E:\MySQL\memory_leak_report.txt
WARNING: Visual Leak Detector detected memory leaks!
---------- Block 65 at 0x0000000068D87EB0: 8 bytes ----------
Leak Hash: 0x38615834, Count: 1, Total 8 bytes
Call Stack (TID 4628):
0x00000000C3EC5630 (File and line number not available): ntdll.dll!RtlAllocateHeap
f:\dd\vctools\crt_bld\self_64_amd64\crt\src\new.cpp (59): MySQLTrials.exe!operator new + 0xA bytes
0x00000000DF30AEE4 (File and line number not available): MySQLTrials.exe!sql::mysql::util::Singleton<sql::mysql::NativeAPI::LibmysqlStaticProxy>::theInstance + 0x44 bytes
0x00000000DF306DB1 (File and line number not available): MySQLTrials.exe!sql::mysql::NativeAPI::getCApiHandle + 0x41 bytes
0x00000000DF2AA5AC (File and line number not available): MySQLTrials.exe!sql::mysql::NativeAPI::MySQL_NativeDriverWrapper::MySQL_NativeDriverWrapper + 0x5C bytes
0x00000000DF2AA51D (File and line number not available): MySQLTrials.exe!sql::mysql::NativeAPI::createNativeDriverWrapper + 0x4D bytes
0x00000000DF28401B (File and line number not available): MySQLTrials.exe!sql::mysql::MySQL_Driver::MySQL_Driver + 0x8B bytes
0x00000000DF28456F (File and line number not available): MySQLTrials.exe!sql::mysql::get_driver_instance_by_name + 0x18F bytes
0x00000000DF284681 (File and line number not available): MySQLTrials.exe!sql::mysql::get_driver_instance + 0x21 bytes
0x00000000DF283E1A (File and line number not available): MySQLTrials.exe!get_driver_instance + 0x1A bytes
e:\mysql\mysql.cpp (22): MySQLTrials.exe!wmain + 0x5 bytes
f:\dd\vctools\crt_bld\self_64_amd64\crt\src\crt0.c (240): MySQLTrials.exe!__tmainCRTStartup + 0x19 bytes
f:\dd\vctools\crt_bld\self_64_amd64\crt\src\crt0.c (164): MySQLTrials.exe!wmainCRTStartup
0x00000000C1CF167E (File and line number not available): KERNEL32.DLL!BaseThreadInitThunk + 0x1A bytes
0x00000000C3EDC3F1 (File and line number not available): ntdll.dll!RtlUserThreadStart + 0x21 bytes
---------- Block 413 at 0x0000000068D90FF0: 40 bytes ----------
Leak Hash: 0x7614B12C, Count: 1, Total 40 bytes
Call Stack (TID 4628):
0x00000000C3EC5630 (File and line number not available): ntdll.dll!RtlAllocateHeap
f:\dd\vctools\crt_bld\self_64_amd64\crt\src\new.cpp (59): MySQLTrials.exe!operator new + 0xA bytes
0x00000000DF30C576 (File and line number not available): MySQLTrials.exe!sql::mysql::NativeAPI::MySQL_NativeConnectionWrapper::stmt_init + 0x86 bytes
0x00000000DF28E730 (File and line number not available): MySQLTrials.exe!sql::mysql::MySQL_Connection::prepareStatement + 0xC0 bytes
e:\mysql\mysql.cpp (30): MySQLTrials.exe!wmain + 0x30 bytes
f:\dd\vctools\crt_bld\self_64_amd64\crt\src\crt0.c (240): MySQLTrials.exe!__tmainCRTStartup + 0x19 bytes
f:\dd\vctools\crt_bld\self_64_amd64\crt\src\crt0.c (164): MySQLTrials.exe!wmainCRTStartup
0x00000000C1CF167E (File and line number not available): KERNEL32.DLL!BaseThreadInitThunk + 0x1A bytes
0x00000000C3EDC3F1 (File and line number not available): ntdll.dll!RtlUserThreadStart + 0x21 bytes
---------- Block 241 at 0x0000000068D93910: 16 bytes ----------
Leak Hash: 0x447A29BE, Count: 1, Total 16 bytes
Call Stack (TID 4628):
0x00000000C3EC5630 (File and line number not available): ntdll.dll!RtlAllocateHeap
c:\program files (x86)\microsoft visual studio 11.0\vc\include\xmemory0 (592): MySQLTrials.exe!std::allocator<std::_Container_proxy>::allocate
0x00000000DF28B052 (File and line number not available): MySQLTrials.exe!std::_Wrap_alloc<std::allocator<std::_Container_proxy> >::allocate + 0x32 bytes
0x00000000DF303CA7 (File and line number not available): MySQLTrials.exe!std::_Deque_alloc<0,std::_Deque_base_types<sql::mysql::MySQL_DebugEnterEvent const * __ptr64,std::allocator<sql::mysql::MySQL_DebugEnterEvent const * __ptr64> > >::_Alloc_proxy + 0x37 bytes
0x00000000DF303991 (File and line number not available): MySQLTrials.exe!std::_Deque_alloc<0,std::_Deque_base_types<sql::mysql::MySQL_DebugEnterEvent const * __ptr64,std::allocator<sql::mysql::MySQL_DebugEnterEvent const * __ptr64> > >::_Deque_alloc<0,std::_Deque_base_types<sql::mysql::MySQL_DebugEnterEvent const * __ptr64,std + 0x41 bytes
0x00000000DF303A95 (File and line number not available): MySQLTrials.exe!std::deque<sql::mysql::MySQL_DebugEnterEvent const * __ptr64,std::allocator<sql::mysql::MySQL_DebugEnterEvent const * __ptr64> >::deque<sql::mysql::MySQL_DebugEnterEvent const * __ptr64,std::allocator<sql::mysql::MySQL_DebugEnterEvent const * __ptr64> > + 0x35 bytes
0x00000000DF303ACB (File and line number not available): MySQLTrials.exe!std::stack<sql::mysql::MySQL_DebugEnterEvent const * __ptr64,std::deque<sql::mysql::MySQL_DebugEnterEvent const * __ptr64,std::allocator<sql::mysql::MySQL_DebugEnterEvent const * __ptr64> > >::stack<sql::mysql::MySQL_DebugEnterEvent const * __ptr64,std::d + 0x2B bytes
0x00000000DF302AFE (File and line number not available): MySQLTrials.exe!sql::mysql::MySQL_DebugLogger::MySQL_DebugLogger + 0x3E bytes
0x00000000DF28CD77 (File and line number not available): MySQLTrials.exe!sql::mysql::MySQL_Connection::MySQL_Connection + 0x227 bytes
0x00000000DF284184 (File and line number not available): MySQLTrials.exe!sql::mysql::MySQL_Driver::connect + 0xA4 bytes
e:\mysql\mysql.cpp (23): MySQLTrials.exe!wmain + 0x5B bytes
f:\dd\vctools\crt_bld\self_64_amd64\crt\src\crt0.c (240): MySQLTrials.exe!__tmainCRTStartup + 0x19 bytes
f:\dd\vctools\crt_bld\self_64_amd64\crt\src\crt0.c (164): MySQLTrials.exe!wmainCRTStartup
0x00000000C1CF167E (File and line number not available): KERNEL32.DLL!BaseThreadInitThunk + 0x1A bytes
0x00000000C3EDC3F1 (File and line number not available): ntdll.dll!RtlUserThreadStart + 0x21 bytes
---------- Block 483 at 0x0000000068D93960: 11 bytes ----------
Leak Hash: 0x1D599652, Count: 1, Total 11 bytes
Call Stack (TID 4628):
0x00000000C3EC5630 (File and line number not available): ntdll.dll!RtlAllocateHeap
f:\dd\vctools\crt_bld\self_64_amd64\crt\src\newaop.cpp (7): MySQLTrials.exe!operator new[]
0x00000000DF32199C (File and line number not available): MySQLTrials.exe!sql::mysql::MySQL_ResultBind::bindResult + 0xA0C bytes
0x00000000DF321379 (File and line number not available): MySQLTrials.exe!sql::mysql::MySQL_ResultBind::bindResult + 0x3E9 bytes
0x00000000DF313F69 (File and line number not available): MySQLTrials.exe!sql::mysql::MySQL_Prepared_ResultSet::MySQL_Prepared_ResultSet + 0x169 bytes
0x00000000DF2EC0E1 (File and line number not available): MySQLTrials.exe!sql::mysql::MySQL_Prepared_Statement::executeQuery + 0x1F1 bytes
e:\mysql\mysql.cpp (33): MySQLTrials.exe!wmain + 0x13 bytes
f:\dd\vctools\crt_bld\self_64_amd64\crt\src\crt0.c (240): MySQLTrials.exe!__tmainCRTStartup + 0x19 bytes
f:\dd\vctools\crt_bld\self_64_amd64\crt\src\crt0.c (164): MySQLTrials.exe!wmainCRTStartup
0x00000000C1CF167E (File and line number not available): KERNEL32.DLL!BaseThreadInitThunk + 0x1A bytes
0x00000000C3EDC3F1 (File and line number not available): ntdll.dll!RtlUserThreadStart + 0x21 bytes
Visual Leak Detector detected 119 memory leaks (640915 bytes).
Largest number used: 697643 bytes.
Total allocations: 837447 bytes.
Visual Leak Detector is now exiting.
Question:
Pourquoi voyons-nous des fuites à la ligne MySQL.cpp (23):
pConnection = driver->connect("tcp://127.0.0.1:3306", "username", "password");
et MySQL.cpp (3 3)
pResultSet= m_pPreparedStatement->executeQuery();
malgré nous supprimons pResultSet
et pConnection
? Pourquoi avons-nous besoin de supprimer pPreparedStatement
ainsi que le jeu de résultats libre?
Je pense que l'auteur veut savoir pourquoi la mémoire de ResultSet reste allouée même lorsque l'objet ResultSet est supprimé. Le RAII n'est pas un problème ici. – gomons
Et je veux le savoir aussi (= – gomons