C++中new分配内存未触发泄漏?原因分析及修改方案
关于C++中new/delete对基本类型的机制与内存泄漏问题
一、new/delete处理基本类型的工作机制
new T[N](比如new int[10000]):直接在堆上分配能容纳N个T类型对象的连续内存空间,因为是基本类型,不会调用构造函数;分配成功后返回指向内存起始地址的指针。delete[] ptr:对应数组形式的new操作,直接释放ptr指向的堆内存空间,同样因为是基本类型,不会调用析构函数;注意必须严格用delete[]匹配数组new,虽然基本类型用普通delete可能不会立刻出问题,但属于未定义行为,绝对不能这么做。
二、无智能指针时的自动内存管理?
不存在。C++里如果不用智能指针(std::unique_ptr/std::shared_ptr等)、自动管理内存的容器(比如std::vector)或者RAII类,堆内存完全需要手动管理——你用new/new[]分配的内存,必须自己用delete/delete[]释放,操作系统只会在程序退出时回收进程所有内存,运行期间不会主动帮你清理堆上的分配。
三、为什么你的代码没出现内存占用增长?
你的代码每次调用MemoryLeak(10000)后就丢失了堆内存的指针,理论上已经造成内存泄漏,但看不到内存增长的原因主要有这几点:
- 内存分配器的缓存机制:C++的内存分配器(比如glibc的ptmalloc)会把“泄漏”的内存缓存起来,下次分配同大小的内存时优先复用缓存,不会立刻还给操作系统,所以操作系统层面看到的进程内存占用不会持续上升。
- 单次分配内存太小:10000个int仅约40KB,现代系统的内存管理对这种小内存块的分配有优化,多次重复分配也很难显现出明显的内存增长。
- 系统内存统计的延迟:任务管理器、top这类工具显示的进程内存数值,不会实时精确反映堆内存的实际分配情况,存在统计滞后或合并计算的可能。
四、如何修改代码触发明显的内存泄漏?
可以从两个方向调整:
- 增大单次分配的内存量,同时保存所有分配的指针,避免分配器复用内存块:
#include <iostream> #include <string> #include <algorithm> #include <vector> int* MemoryLeak(const int size) { std::cout << "Allocating space for " << size << " ints..." << std::endl; return new int[size]; } int main() { std::string keepGoing = "y"; std::vector<int*> leakedPtrs; // 保存所有分配的指针,让内存无法被复用 while (keepGoing != "n") { std::cout << "Leak memory? [y/n]" << std::endl; std::cin >> keepGoing; std::transform(keepGoing.begin(), keepGoing.end(), keepGoing.begin(), ::tolower); if (keepGoing == "y") { leakedPtrs.push_back(MemoryLeak(1000000)); // 单次分配约4MB内存 } else if (keepGoing != "n") { keepGoing = "y"; } } }
运行这段代码,每次输入y都会分配一块新的4MB内存,且指针被容器保存,分配器无法复用之前的内存,你能明显看到进程内存占用持续增长。
内容的提问来源于stack exchange,提问作者fe.dev
相关产品推荐
相关产品推荐

