了解Microsoft的内存泄漏检测输出

Making sense of Microsoft's Memory Leak Detection output

本文关键字:检测 输出 泄漏 内存 Microsoft 了解      更新时间:2023-10-16

很抱歉标题不正确,但我只是好奇内存泄漏到底是什么,我怎么能说我在程序中做了一些坏事。

我在Visual Studio中运行了内存泄漏测试(_CrtDumpMemoryLeaks()),它输出了一个检测到的泄漏的巨大列表(只显示了一小部分):

{1640} normal block at 0x081C2AB0, 4 bytes long.
Data: <;   > 3B 00 00 00 
{789} normal block at 0x08B792E8, 12 bytes long.
Data: <            > 00 00 00 00 00 00 00 00 00 00 00 00 
{788} normal block at 0x027E62D8, 32 bytes long.
Data: <         L   L  > 20 A8 FE 07 A0 A0 17 08 E4 4C F3 07 D8 4C F3 07 
{787} normal block at 0x027E6328, 32 bytes long.
Data: <layer03 - Object> 6C 61 79 65 72 30 33 20 2D 20 4F 62 6A 65 63 74 
{786} normal block at 0x08B79748, 8 bytes long.
Data: <`N      > 60 4E F3 07 00 00 00 00

我真的不明白,我到底做错了什么。我遵循了我另一个问题的提示,用智能指针替换了所有new/delete内容(或者至少我认为我做到了)。

我之所以这么问,是因为我在运行程序时遇到了内存大小和堆大小的增加,我不确定这是什么严重的问题还是某种基本行为。

以我的(自写的)gui为例:

std::shared_ptr<Gui_Button> gui_modal_window_map_saved_button;

我现在称之为:

gui_modal_window_map_saved_button.reset(new Gui_Button(res_handler, "Select", 20, 345, 70, 40, BUTTON_CONFIRM));

它被告知是记忆安全的。现在,有一件事我真的不确定——我现在如何安全地删除按钮?我知道,没有什么比智能指针删除更好的了,但我认为删除的方式是在不再需要按钮时删除按钮,即在相应的窗口关闭后。

现在我正在用reset()"删除"我的按钮

if (g_ev.event_id == EVENT_CLICKED && g_ev.element == gui_modal_window_map_saved_button.get()) {
gui_modal_window_map_saved.reset();
gui_modal_window_map_saved_button.reset();
}

我认为这还可以,但为什么每次创建"新"按钮时,我的内存大小都会增加(而不是再次减少)?

回到最初的问题

我通过Visual Studio得到了这些内存泄漏的转储,但我真的不知道如何使用这些信息。内存泄漏的确切原因是什么?我现在只使用"普通"指针,在那里我需要将一些东西传递给另一个类,即,并用智能指针替换了所有new/deletes。我真的无法显示我的代码,因为到目前为止大约有3000行。。

那么,究竟是什么导致了内存泄漏,我该如何使用VS提供的信息呢?

Microsoft提供了有关如何利用您看到的数据的详细信息:https://msdn.microsoft.com/en-us/library/x98tx3cf.aspx

可以使用分配编号在进行分配时插入代码。在调试输出的以下行中:

{789} normal block at 0x08B792E8, 12 bytes long.

789是分配编号。你提到内存的使用正在增长。这并不一定意味着泄漏不断增加,除非在执行更长会话时泄漏消息相应增加。

另一件需要考虑的事情是,泄漏发生在您的类中。如果您的对象中分配了任何未正确处理的元素,则没有智能指针可以保存您。

C++与许多较新语言的不同之处在于,它没有所谓的垃圾收集器。您使用new分配(声明)内存,并使用delete再次显式解除分配(释放)内存。

如果忘记了delete,则只有在程序存在后,操作系统才会释放内存。

为了平衡newdelete的使用,如果可能的话,只在构造函数中分配内存,并在(虚拟)析构函数中解除分配。通过这种方式,如果拥有一块堆内存(用new分配的内存)的对象超出范围(例如,在离开函数时是一个局部变量),则该内存将自动释放。

顺便说一句,以这种方式分配和释放内存是赋予C++多功能性和速度的因素之一。因此,这是一种资产,而不是需要避免的东西。但它需要小心使用。