问题 
我一直在寻找类似的帖子,但找不到适合我的问题的帖子。 
 
我正在尝试制作一个使用 MySQL 数据库进行查询的基本程序,并且一切正常,但是我有很多内存泄漏。 
- #include <cppconn/driver.h>
 
  
- #include <crtdbg.h>
 
  
- int main() {
 
  
-     {
 
 -         sql::Driver* driver = get_driver_instance();
 
 -     }
 
  
-     _CrtDumpMemoryLeaks();
 
 -     return 0;
 
 - }
 
 
  复制代码 
这是我正在使用的一小部分。其余的并不真正相关,因为我观察到即使是一小段代码也会产生大量内存泄漏,正如 CrtDumpMemoryLeaks 调用所给出的那样。 
 
我得到了 64 位版本并使用了动态链接库。我观察到我还需要单独链接boost库,所以我下载了它并把它的“包含”目录中也是如此。 
 
我正在使用 Visual Studio 2019 社区。 
 
任何帮助将不胜感激。干杯! 
 
这是运行程序后的输出。 
- Detected memory leaks!
 
 - Dumping objects ->
 
 - {193} normal block at 0x0000014FB1F74710, 16 bytes long.
 
 -  Data: < F  O           > 90 46 FA B1 4F 01 00 00 00 00 00 00 00 00 00 00 
 
 - {192} normal block at 0x0000014FB1FA4670, 88 bytes long.
 
 -  Data: < (  O    (  O   > 00 28 F6 B1 4F 01 00 00 00 28 F6 B1 4F 01 00 00 
 
 - {191} normal block at 0x0000014FB1F8CC30, 24 bytes long.
 
 -  Data: <  g             > 18 03 67 C5 FE 7F 00 00 01 00 00 00 01 00 00 00 
 
 - {190} normal block at 0x0000014FB1F8C7B0, 24 bytes long.
 
 -  Data: <  d             > A8 96 64 C5 FE 7F 00 00 02 00 00 00 01 00 00 00 
 
 - {189} normal block at 0x0000014FB1F5E280, 104 bytes long.
 
 -  Data: <                > FF FF FF FF FF FF FF FF FF FF FF FF 00 00 00 00 
 
 - {188} normal block at 0x0000014FB1F57FE0, 168 bytes long.
 
 -  Data: <                > 00 00 00 00 D2 04 00 00 88 00 00 00 00 00 00 00 
 
 - {187} normal block at 0x0000014FB1F5F5A0, 104 bytes long.
 
 -  Data: <                > FF FF FF FF FF FF FF FF FF FF FF FF 00 00 00 00 
 
 - {186} normal block at 0x0000014FB1F61720, 56 bytes long.
 
 -  Data: <                > 00 00 00 00 D2 04 00 00 18 00 00 00 00 00 00 00 
 
 - {185} normal block at 0x0000014FB1F71050, 48 bytes long.
 
 -  Data: <                > 00 00 00 00 D2 04 00 00 10 00 00 00 00 00 00 00 
 
 - {184} normal block at 0x0000014FB1F70DB0, 40 bytes long.
 
 -  Data: <        p   O   > 00 00 00 00 CD CD CD CD 70 10 F7 B1 4F 01 00 00 
 
 - {183} normal block at 0x0000014FB1F70D40, 48 bytes long.
 
 -  Data: <                > 00 00 00 00 D2 04 00 00 10 00 00 00 00 00 00 00 
 
 - {182} normal block at 0x0000014FB1F710C0, 40 bytes long.
 
 -  Data: <        `   O   > 00 00 00 00 CD CD CD CD 60 0D F7 B1 4F 01 00 00 
 
 - {181} normal block at 0x0000014FB1F64C10, 80 bytes long.
 
 -  Data: <h i     dRi     > 68 C6 69 C5 FE 7F 00 00 64 52 69 C5 FE 7F 00 00 
 
 - {180} normal block at 0x0000014FB1F743F0, 16 bytes long.
 
 -  Data: <         L  O   > 01 00 00 00 00 00 00 00 10 4C F6 B1 4F 01 00 00 
 
 - {179} normal block at 0x0000014FB1F5BF60, 104 bytes long.
 
 -  Data: <                > FF FF FF FF FF FF FF FF FF FF FF FF 00 00 00 00 
 
 - {178} normal block at 0x0000014FB1F57280, 104 bytes long.
 
 -  Data: <                > FF FF FF FF FF FF FF FF FF FF FF FF 00 00 00 00 
 
 - {177} normal block at 0x0000014FB1F55310, 104 bytes long.
 
 -  Data: <                > FF FF FF FF FF FF FF FF FF FF FF FF 00 00 00 00 
 
 - {176} normal block at 0x0000014FB1F55560, 104 bytes long.
 
 -  Data: <                > FF FF FF FF FF FF FF FF FF FF FF FF 00 00 00 00 
 
 - {175} normal block at 0x0000014FB1F5E560, 104 bytes long.
 
 -  Data: <                > FF FF FF FF FF FF FF FF FF FF FF FF 00 00 00 00 
 
 - {174} normal block at 0x0000014FB1F55EE0, 104 bytes long.
 
 -  Data: <                > FF FF FF FF FF FF FF FF FF FF FF FF 00 00 00 00 
 
 - {173} normal block at 0x0000014FB1F57530, 104 bytes long.
 
 -  Data: <                > FF FF FF FF FF FF FF FF FF FF FF FF 00 00 00 00 
 
 - {172} normal block at 0x0000014FB1F57C50, 104 bytes long.
 
 -  Data: <                > FF FF FF FF FF FF FF FF FF FF FF FF 00 00 00 00 
 
 - {171} normal block at 0x0000014FB1F57960, 104 bytes long.
 
 -  Data: <                > FF FF FF FF FF FF FF FF FF FF FF FF 00 00 00 00 
 
 - {170} normal block at 0x0000014FB1F744E0, 8 bytes long.
 
 -  Data: <8 d     > 38 94 64 C5 FE 7F 00 00 
 
 - {169} normal block at 0x0000014FB1F62560, 24 bytes long.
 
 -  Data: <0 d      D  O   > 30 8C 64 C5 FE 7F 00 00 E0 44 F7 B1 4F 01 00 00 
 
 - {168} normal block at 0x0000014FB1F743A0, 16 bytes long.
 
 -  Data: <  f     `%  O   > F0 FE 66 C5 FE 7F 00 00 60 25 F6 B1 4F 01 00 00 
 
 - {167} normal block at 0x0000014FB1F62800, 88 bytes long.
 
 -  Data: <pF  O   pF  O   > 70 46 FA B1 4F 01 00 00 70 46 FA B1 4F 01 00 00 
 
 - {166} normal block at 0x0000014FB1F74850, 16 bytes long.
 
 -  Data: < s              > 98 73 E1 C5 FE 7F 00 00 00 00 00 00 00 00 00 00 
 
 - {162} normal block at 0x0000014FB1F65510, 80 bytes long.
 
 -  Data: < U  O    U  O   > 10 55 F6 B1 4F 01 00 00 10 55 F6 B1 4F 01 00 00 
 
 - {161} normal block at 0x0000014FB1F74F30, 16 bytes long.
 
 -  Data: <                > D8 D4 E1 C5 FE 7F 00 00 00 00 00 00 00 00 00 00 
 
 - {160} normal block at 0x0000014FB1F73080, 120 bytes long.
 
 -  Data: < 0  O    0  O   > 80 30 F7 B1 4F 01 00 00 80 30 F7 B1 4F 01 00 00 
 
 - {159} normal block at 0x0000014FB1F74D00, 16 bytes long.
 
 -  Data: <                > F0 D4 E1 C5 FE 7F 00 00 00 00 00 00 00 00 00 00 
 
 - {158} normal block at 0x0000014FB1F750C0, 16 bytes long.
 
 -  Data: <hs              > 68 73 E1 C5 FE 7F 00 00 00 00 00 00 00 00 00 00 
 
 - {157} normal block at 0x0000014FB1F72FE0, 88 bytes long.
 
 -  Data: < /  O    /  O   > E0 2F F7 B1 4F 01 00 00 E0 2F F7 B1 4F 01 00 00 
 
 - {156} normal block at 0x0000014FB1F74350, 16 bytes long.
 
 -  Data: < X              > 00 58 E1 C5 FE 7F 00 00 00 00 00 00 00 00 00 00 
 
 - Object dump complete.
 
  复制代码 
所以看起来有很多东西泄漏只是在驱动程序类上调用该方法。析构函数是受保护的,所以我不能调用“delete”在上面。 
 
回答 
这并不是真正的内存泄漏,因为您“过早”检查。 
 
在这里可以看到 get_driver_instance 是如何实现的: 
- static std::map< sql::SQLString, boost::shared_ptr<MySQL_Driver> > driver;
 
  
- CPPCONN_PUBLIC_FUNC sql::mysql::MySQL_Driver * get_driver_instance()
 
 - {
 
 -     return get_driver_instance_by_name("");
 
 - }
 
  
 
- CPPCONN_PUBLIC_FUNC sql::mysql::MySQL_Driver * get_driver_instance_by_name(const char * const clientlib)
 
 - {
 
 -     ::sql::SQLString dummy(clientlib);
 
  
-     std::map< sql::SQLString, boost::shared_ptr< MySQL_Driver > >::const_iterator cit;
 
  
-     if ((cit = driver.find(dummy)) != driver.end()) {
 
 -         return cit->second.get();
 
 -     } else {
 
 -         boost::shared_ptr< MySQL_Driver > newDriver;
 
  
-         newDriver.reset(new MySQL_Driver(dummy));
 
 -         driver[dummy] = newDriver;
 
  
-         return newDriver.get();
 
 -     }
 
 - }
 
  复制代码 
您可以看到创建了一个全局变量驱动程序,它是 shared_ptr 到可视 MySQL_Driver 对象的映射。 get_driver_instance 只需调用 get_driver_instance_by_name("") 以返回驱动程序 driver[""] 或创建驱动程序(如果它不存在)。 
 
在 shared_ptr 文档中,您可以看到 shared_ptr 在销毁自身时会删除分配给 shared_ptr 的指针。当地图驱动程序被销毁时,它将被销毁,这将在进程被销毁时发生 - 在 main 返回之后。 
 
因此,在 main 中,驱动程序仍然存在(析构函数尚未运行),所以 _CrtDumpMemoryLeaks();会将它们报告为虚假泄漏。 
 
这基本上就是这里描述的问题。 
 
但是,我不确定是否有可靠的方法在析构函数之后运行代码,因为全局析构函数和 atexit 处理程序的运行顺序并未在不同的翻译单元中指定。 
 
由于您在 Windows 上,一个想法是(ab)使用线程本地存储回调,您可以在 DLL_THREAD_DETACH 步骤中运行您的代码,据我所知,它应该在常规析构函数等之后运行。请参阅本文。 (虽然我不确定,但如果有人能比我更了解这一点,我会很高兴!) 
 
 
 
 |