C++之vector内存释放原理
作者:幽_篁
C++ vector内存释放
C++ STL容器 vector 的工作原理
vector容器的元素以连续方式存放,每一个元素都紧挨着前一个元素存储,类似数组的内存结构。
系统预先给vector容器分配一块 capactity 大小的内存空间,当插入的数据超过这个空间的时候,这块空间会让某种方式扩展,即通过一定倍数大小重新分配空间、拷贝元素、撤销旧空间,在vs下为1.5倍扩容,在linux下为2倍扩容。但是为了防止大量分配连续内存的开销,在使用clear和erase删除数据的时候,它只做了数据清除工作,没有释放内存,所以vector容器的内存是不会缩小的。
也就是说,vector容器实现内存自增长,在vector对象不释放的情况下内存只会增长而不会释放,只有当vector对象销毁才会释放这个内存。
如下示例,打印使用clear和erase删除数据前后vector对象的数据容量和内存容量大小
#include <iostream> #include <vector> using namespace std; int main(void) { vector<int> vt; for (int i = 0; i < 10; i++) { vt.push_back(i); } cout << "size:" << vt.size() << endl; cout << "capacity:" << vt.capacity() << endl; #if 0 vt.clear(); #else for (auto item = vt.begin(); item != vt.end(); ) { item = vt.erase(item); } #endif cout << "size:" << vt.size() << endl; cout << "capacity:" << vt.capacity() << endl; system("pause"); return 0; }
使用clear和erase删除数据测试结果入下:
从示例不难看出使用clear和erase无法释放vector容器内存,那对于vector容器,我们应该如何释放呢?
最简单的就是使用 swap()交换函数,使vector离开其自身的作用域,从而强制释放vector所占的内存空间。
template < class T > void ClearVector( vector< T >& vt ) { vector< T > vtTemp; veTemp.swap( vt ); }
一般的STL内存管理器allocator都是用内存池来管理内存的,所以某个容器申请内存或释放内存都只是影响到内存池的剩余内存量,而不是真的把内存归还给系统。
这样做一是为了避免内存碎片,二是提高了内存申请和释放的效率。
事实上,vector容器在内存不够时就向内存管理框架申请内存,内存管理框架如果发现内存不够了,就malloc内存,但是当vector释放资源的时候(比如destruct), stl根本就不调用free以减少内存,因为内存分配在stl的底层:stl假定如果你需要更多的资源就代表你以后也可能需要这么多资源(你的list, hashmap也是用这些内存),所以就没必要不停地malloc/free。
注意:这边说到的是系统分配的内存的申请/释放。如果vector中存放的是指针,那么当vector销毁时,这些指针指向的对象不会被销毁,那么内存就不会被释放。开发者自己申请的内存记得自己释放。
C++容器vector内存释放问题
突然遇到vector在使用clear之后,其内存(capacity不变)无法释放的问题:
vector<int> v1{1,2,3}; cout << v1.empty() << endl; cout << v1[0] << " " << v1.size() << " " << v1.capacity() << endl; v1.clear(); cout << v1.empty() << endl; cout << v1[0] << " " << v1.size() << " " << v1.capacity() << endl;
输出结果:
0
1 3 3
1
1 0 3
0 3
可以发现,在使用clear之后,size和empty改变了,但是capacity依旧是那么大(总算是理解C++Primer:vector在生命周期内,内存大小是只增不减)。
这里提供两种释放方法
第一种:
作用域+临时变量+swap函数:swap函数可以直接交换容器的内存
{ std::vector<int>().swap(v1); } cout << v1.size() << " " << v1.capacity() << endl;
运行结果:
0 0
第二种:
不易发现的成员函数:shrink_to_fit去释放。
v1.shrink_to_fit(); cout << v1.size() << " " << v1.capacity() << endl;
运行结果:
0 0
但是,虽然clear之后vector的内存不会释放,但是重新emplace_back之后的数据,会从容器内存起始地址开始重新存放。
总结
以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。