std::vector调用clear未释放内存?正常现象还是自定义分配器问题?
关于std::vector::clear不释放内存的问题及解决方法
我正在编写一个用于追踪内存消耗的MemoryTracker类,使用自定义分配器创建std::vector后,发现调用std::vector::clear时并未释放内存。想了解这是否属于正常情况,或是我的自定义分配器存在问题;若为正常情况,该如何强制vector释放内存?
一、clear()不释放内存是正常行为
std::vector的clear()方法只会销毁容器内的元素(调用元素的析构函数),但不会释放底层分配的内存空间。这是标准库的设计意图——保留已分配的内存,避免后续再次添加元素时重复分配内存带来的性能开销。你的MemoryTracker显示内存未释放,完全符合预期,不是自定义分配器的问题。
二、你的自定义分配器是否存在问题?
从提供的代码来看,你的TrackingAllocator实现符合C++标准分配器要求:
- 正确实现了
allocate/deallocate接口,调用MemoryTracker完成内存追踪 - 实现了必要的类型别名、构造/拷贝构造函数
- 正确重载了
operator==和operator!=(所有TrackingAllocator实例视为等价,符合标准规范)
仅需注意:_NODISCARD是C17特性,需确保编译环境支持;另外_Ty作为模板参数名,按C惯例通常避免下划线开头(仅风格问题,不影响功能)。
三、如何强制vector释放内存?
有三种可靠方法可让vector释放底层内存:
1. swap技巧
创建临时空vector,与目标vector交换内容。临时vector销毁时会自动释放内存:
// 简洁写法 data::vector<short int>().swap(v);
2. C++11及以后:shrink_to_fit()
调用shrink_to_fit()请求vector将容量缩减至与当前元素数量匹配。这是标准库的请求性接口,主流编译器(GCC、Clang、MSVC)都会执行内存释放:
v.clear(); v.shrink_to_fit();
3. 赋值空vector
直接给目标vector赋值空临时vector,效果与swap一致:
v = data::vector<short int>();
附:完整代码
main.cpp
#include <iostream> #include <vector> #include "memory.hpp" int main() { { std::cout << "\ncreating vector\n"; data::vector<short int> v; std::cout << "\nreserving 100 elements\n"; v.reserve(100); std::cout << data::MemoryTracker::Bytes_in_use() << " bytes allocated\n"; for (int i = 0; i < 100; ++i) { v.push_back(i); } std::cout << "\npushing one extra element\n"; v.push_back(0); std::cout << "\nclearing vector\n"; v.clear(); std::cout << data::MemoryTracker::Bytes_in_use() << " bytes allocated\n"; v.resize(0); std::cout << "\npushing 1 element\n"; v.push_back(0); std::cout << data::MemoryTracker::Bytes_in_use() << " bytes allocated\n"; std::cout << "\nleaving scope\n"; } std::cout << data::MemoryTracker::Bytes_in_use() << " bytes allocated\n"; return 0; }
memory.hpp
#ifndef _MEMORY_HPP_ #define _MEMORY_HPP_ #include <iostream> #include <vector> namespace data{ class MemoryTracker { template <typename T> friend class TrackingAllocator; private: static _NODISCARD void *allocate(size_t size) { std::cout << "allocating " << size << " bytes\n"; bytes_in_use += size; return std::malloc(size); } static void deallocate(void *ptr, size_t size) { std::cout << "freeing " << size << " bytes\n"; bytes_in_use -= size; std::free(ptr); // ::operator delete[](ptr); } public: static size_t Bytes_in_use() { return bytes_in_use; } private: static size_t bytes_in_use; }; size_t MemoryTracker::bytes_in_use = 0; template <typename T> class TrackingAllocator { // friend class MemoryTracker; public: friend bool operator==(const TrackingAllocator &, const TrackingAllocator &) { return true; } friend bool operator!=(const TrackingAllocator &, const TrackingAllocator &) { return false; } public: using value_type = T; using pointer = T *; using const_pointer = const T *; using reference = T &; using const_reference = const T &; using size_type = size_t; using difference_type = ptrdiff_t; TrackingAllocator() = default; template <typename U> TrackingAllocator(const TrackingAllocator<U> &) {}; _NODISCARD pointer allocate(size_type n) { return static_cast<pointer>(MemoryTracker::allocate(n * sizeof(value_type))); } void deallocate(pointer p, size_type n) { MemoryTracker::deallocate(p, n * sizeof(value_type)); } template <typename U, typename... Args> void construct(U *p, Args &&...args) { ::new ((void *)p) U(std::forward<Args>(args)...); } void destroy(pointer p) noexcept { p->~value_type(); } }; template <class _Ty> class vector : public std::vector<_Ty, TrackingAllocator<_Ty>>{}; } #endif
内容的提问来源于stack exchange,提问作者Victor
相关产品推荐
相关产品推荐

