【问题标题】:Memory leak in Valgrind using newValgrind 中的内存泄漏使用 new
【发布时间】:2020-01-29 12:22:11
【问题描述】:

这个例子可能很糟糕,但这就是当我跟踪 Valgrind 显示的堆栈帧时的样子。 LocationList、Location、FolderList 和 Folder 是不同的类,我只粘贴了这些类的复制构造函数和赋值运算符。但我不确定为什么会出现内存泄漏。

我知道我在复制构造函数中使用了 new 运算符和 for 循环,这可能是造成问题的原因,但我不确定如何处理。这是 Valgrind 的调用堆栈。

==15733== 8 bytes in 1 blocks are definitely lost in loss record 28 of 1,002
==15733==    at 0x4A07152: operator new[](unsigned long) (vg_replace_malloc.c:363)
==15733==    by 0x54FA25: FolderList::operator=(FolderList const&) (Folder.h:63)
==15733==    by 0x54FD8A: Server::operator=(Server const&) (Server.h:22)
==15733==    by 0x550631: Location::operator=(Location const&) (Location.h:44)
==15733==    by 0x5507AC: LocationList::LocationList(LocationList const&) (Location.h:76)
==15733==    by 0x54988C: VPSyncInterface::login(std::string, std::string, VPStatus*) (vpsync.cc:365)
==15733==    by 0x549AD5: VPSyncInterface::connect(std::string, std::string, VPStatus*) (vpsync.cc:382)
==15733==    by 0x548FF0: VPSyncInterface::reconnect(VPStatus*) (vpsync.cc:227)
==15733==    by 0x548D39: VPSyncInterface::initialize(VPStatus*, int) (vpsync.cc:175)
==15733==    by 0x42E5B4: ProcessImageImpl::ProcessImageImpl(char const*, int, char const*, int) (ProcessImageImpl.cc:172)
==15733==    by 0x426FDD: cvRetrievalImpl::getProcessObject(cvRetrieval::ProcessType, char const*, int, char const*, int) (cvRetrievalImpl.cc:70)
==15733==    by 0x426B4A: main (ThinIMAGEd.cc:727)

下面是代码栈:

cvRetrievalImpl.cc
    69   case cvRetrieval::PROCESS_IMAGE:
    70     return new ProcessImageImpl (application_class, instance_wants_to_access_vp, auth_group, threadCount);
    71     break;

ProcessImageImpl.cc

    VPStatus init_status;
    if (syncInterface->initialize (&init_status) != 0)
    {
        cvLog (CV_LOG_FATAL, "Cannot initialize VP sync interface: %s", 
                    init_status.interpret_current_status());
         exit (EXIT_FAILURE);
    }        

vpsync.cc            
    364     LogonXMLParser* parser = new LogonXMLParser ();
    365     AddDtd *aDtd = new AddDtd (application_class);
    366     string logonOutputXML = aDtd->add (out_xml, process);
    367    
    368     LocationList *vp_locations;
    369     vp_locations = parser->doParse ((const XMLByte*) logonOutputXML.c_str (), logonOutputXML.size ());
    370     delete aDtd;

    378     if (locations)
    379         delete locations;
    380     // We have to make a private copy of the locations returned by the parser,
    381     // because the parser's copy will disappear when the parser is destroyed.
    382     locations = new LocationList (*vp_locations);
    383     delete parser;


LocationList& operator= (const LocationList& list)
    79             {
    80             if (this == &list)
    81                 return *this;
    82             incr = list.incr;
    83             curr_size = list.curr_size;
    84             curr_capacity = list.curr_capacity;
    85             if (locations)
    86                 delete [] locations;
    87             locations = new Location[curr_capacity];
    88             for (unsigned int i = 0; i < curr_size; i++)
    89                 locations[i] = list.locations[i];
    90             return *this;
    91             }

Location.h
    39         Location& operator= (const Location& location)
    40             {
    41             if (this == &location)
    42                 return *this;
    43             locationName = location.locationName;
    44             server = location.server;
    45             servers = location.servers;
    46             return *this;
    47             }

Server.h
    16         Server& operator= (const Server& server)
    17             {
    18             if (this == &server)
    19                 return *this;
    20             serverName = server.serverName;
    21             folder = server.folder;
    22             folders = server.folders;
    23             return *this;
    24             }

Folder.h

    54         FolderList& operator= (const FolderList& list)
    55             {
    56             if (this == &list)
    57                 return *this;
    58             incr = list.incr;
    59             curr_size = list.curr_size;
    60             curr_capacity = list.curr_capacity;
    61             if (folders)
    62                 delete [] folders;
    63             folders = new Folder[curr_capacity];
    64             for (unsigned int i = 0; i < curr_size; i++)
    65                 folders[i] = list.folders[i];
    66             return *this;
    67             }

    16         Folder& operator= (const Folder& folder)
    17             {
    18             if (this == &folder)
    19                 return *this;
    20             folderName = folder.folderName;
    21             folderDesc = folder.folderDesc;
    22             return *this;
    23             }

【问题讨论】:

  • 您使用new 分配一个新对象,并且从不使用delete 释放它。通过使用shared_ptrunique_ptr,现代C++ 通常可以避免使用new。如果你不能使用这些,你必须确保你分配的每个对象最终都被释放。
  • 我认为FolderList 类的成员字段名为folders。是~FolderList() 中的deleted 吗?所有FolderLists 反过来都被破坏了吗?
  • 限制是我不能在具有唯一和共享指针的代码中使用 C++11。因为 gcc 不支持这个。
  • As gcc doesn't support this. gcc 支持它,您的版本(可能不太可能)、编译器标志或您开发的环境(如果您进行嵌入式开发可能就是这种情况)可能不支持它.
  • Karan,您写道“我只粘贴了复制构造函数和赋值运算符”。我只能看到赋值运算符,没有构造函数。一般来说,如@PaulFloyd 建议的那样,更喜欢为您管理存储的容器。

标签: c++ memory-leaks valgrind


【解决方案1】:

您的漏洞似乎很多 (loss record 28 of 1,002)。

首先,一件小事。在 C++ 中,您不需要在删除指针之前检查它是否为非 NULL。所以

if (folders)
    delete [] folders;

可以替换为

delete [] folders;

接下来,你说你不能使用智能指针。如果能使用标准库容器就更好了。

因此,不要将folders 定义为指向Folder 的指针并写入

if (folders)
   delete [] folders;
folders = new Folder[curr_capacity];
for (unsigned int i = 0; i < curr_size; i++)
    folders[i] = list.folders[i];

您可以定义std::vector&lt;Folder&gt; folders;(而不是我认为您目前拥有的Folder* folders;)并编写

folders = list.folders;

这样做的其他好处:

  1. 您无需管理向量的内存。
  2. 不需要 curr_size 和 cur_capacity - std::vector 提供这些

【讨论】:

  • 感谢其他泄漏可能是泄漏,我稍后会检查。我试过这个,它说“错误:'folders = list->FolderList::folders 中的'operator ='不匹配'
  • Valgrind(至少是 memcheck)的误报率很低。泄漏按增加大小排序,因此我建议从列表末尾的泄漏开始。
猜你喜欢
  • 2013-06-24
  • 1970-01-01
  • 2020-03-31
  • 2016-03-15
  • 2014-04-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多