C++ 中的 new/delete 导致奇怪的内存泄漏

Posted

技术标签:

【中文标题】C++ 中的 new/delete 导致奇怪的内存泄漏【英文标题】:Strange Memory leak by new/delete in C++ 【发布时间】:2018-02-02 10:05:32 【问题描述】:

下面是我的问题和代码:

    当代码运行到第26行时,这个进程获得的内存没有返回给OS? 但是,如果我删除第16行,内存会被正确释放吗?

我知道这不是使用这么多小内存块的常规方式,但我很想知道原因。

我用MALLOC_MMAP_MAX_=1000000 MALLOC_MMAP_THRESHOLD_=1024, 运行了这个程序,但没有任何改变。

int i = 0;
std::cout << "waitting for input, you can check current memory" << std::endl;
std::cin >> i;
char** ptr = new char *[1000000];
std::map<int, char *> tMap;
for (unsigned long i = 0; i < 1000000; i ++)

    ptr[i] = new char[3000];
    tMap.insert(make_pair(i, ptr[i]));    //line 16

std::cout << "waitting for input, you can check current memory" << std::endl;
std::cin >> i;
for (unsigned long i = 0; i < 1000000; i ++)

    delete []ptr[i];

delete []ptr;
std::cout << "waitting for input, you can check current memory" << std::endl;
std::cin >> i;   //line 26
return 0;

这里的资料比较多,我查过tMap的内存,不到100M。

1、分配内存并停止,检查内存资源:

holds 2.9G memory

2、释放内存并停止,检查内存资源:

holds 2.9G memory

【问题讨论】:

你怎么知道的? 请注意,您周围有几个名为i 的变量,这很危险,可能会导致编译器使用您认为会使用的另一个变量。它在这里可能很好用,但这是一种危险的习惯,避免它。 【参考方案1】:

C++ 没有垃圾回收,因此保留一个额外的指针副本不会阻止内存被释放。

delete[] ptr[i] 之后发生的事情是地图充满了无法再使用的悬空指针。


另一个想法:您可能看到的内存泄漏是tMap 分配动态内存来存储插入的数据。当地图超出范围时,该内存将被释放,就在第 27 行之后。

【讨论】:

感谢您的回答,我检查了tMap的内存,与100万个3000字节的块相比,这没什么大不了的。我添加了两张图片来显示内存状态。希望这将有助于解释我的问题。【参考方案2】:

1、当代码运行到第26行时,该进程获得的内存没有返回给OS?

不能保证任何内存都会被 C++ 程序释放到操作系统,因为它被程序正确地分配了 deleted。在许多 C++ 运行时中,被删除的动态分配内存仍将保留同一程序供将来使用,而不是释放给操作系统。 GCC/Linux 是编译器/运行时环境的一个示例,其中更大的分配通常在共享内存段中完成,这些内存段可以在程序终止之前释放给操作系统,以便操作系统或其他程序可以使用它们。

2、但是,如果我删除第16行,内存会被正确释放吗?

第 16 行对稍后在第 22 行删除/释放内存没有任何影响(这可能会将其返回到应用程序稍后可能重新分配的动态内存池,或实际将其释放给操作系统正如刚才提到的)。不过,它确实涉及对 std::map 元素本身的更多动态分配。

请注意,tMap 析构函数本身不会delete 或以任何方式释放内存。要自动释放内存(通过类似指针的变量或容器),请使用 智能指针,例如 std::shared_ptrstd::unique_ptr(您可以在 Google 上搜索相关信息)。

【讨论】:

感谢您的回答,有一些关键词可能会有很大帮助。通过分配大内存块而不是许多小块已经避免了这个问题。我发布这个问题只是为了了解 C 或 C++ 内存管理的一些细节。 大页面是好的。仍然:“问题已被避免” - 这实际上是一个重大问题吗?操作系统倾向于使用 virtual memory 并将某些磁盘配置为 swap - 发生的情况是您的程序已分配但最近未使用的内存内容(并且所有已删除的内存都不应该一直在使用,直到新的分配重新使用)可以复制到磁盘,然后分配给其他程序的物理内存。一般来说,只有当你发现你的电脑速度慢到无法接受时,这才是真正的问题,而不仅仅是因为topps 中的内存使用数字看起来很吓人...... 你是对的。记忆还在这里。删除后,我尝试分配更多内存,但堆不再增长。最合理的解释是 tMap 将内存块分开,很难找到大于指定大小的连续块,然后没有内存返回给操作系统。我将继续研究细节。非常感谢您的帮助。

以上是关于C++ 中的 new/delete 导致奇怪的内存泄漏的主要内容,如果未能解决你的问题,请参考以下文章

C++ 中的 new/delete 和 new[]/delete[]深入理解

C++ new delete操作符

C++ 动态内存 new/delete用法

malloc/free与new/delete的区别与联系

Effective C++笔记(11)—定制new和delete

C++—new/delete/malloc/free详解