C++之vector內(nèi)存釋放原理
C++ vector內(nèi)存釋放
C++ STL容器 vector 的工作原理
vector容器的元素以連續(xù)方式存放,每一個(gè)元素都緊挨著前一個(gè)元素存儲(chǔ),類似數(shù)組的內(nèi)存結(jié)構(gòu)。
系統(tǒng)預(yù)先給vector容器分配一塊 capactity 大小的內(nèi)存空間,當(dāng)插入的數(shù)據(jù)超過這個(gè)空間的時(shí)候,這塊空間會(huì)讓某種方式擴(kuò)展,即通過一定倍數(shù)大小重新分配空間、拷貝元素、撤銷舊空間,在vs下為1.5倍擴(kuò)容,在linux下為2倍擴(kuò)容。但是為了防止大量分配連續(xù)內(nèi)存的開銷,在使用clear和erase刪除數(shù)據(jù)的時(shí)候,它只做了數(shù)據(jù)清除工作,沒有釋放內(nèi)存,所以vector容器的內(nèi)存是不會(huì)縮小的。
也就是說,vector容器實(shí)現(xiàn)內(nèi)存自增長,在vector對(duì)象不釋放的情況下內(nèi)存只會(huì)增長而不會(huì)釋放,只有當(dāng)vector對(duì)象銷毀才會(huì)釋放這個(gè)內(nèi)存。
如下示例,打印使用clear和erase刪除數(shù)據(jù)前后vector對(duì)象的數(shù)據(jù)容量和內(nèi)存容量大小
#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刪除數(shù)據(jù)測試結(jié)果入下:

從示例不難看出使用clear和erase無法釋放vector容器內(nèi)存,那對(duì)于vector容器,我們應(yīng)該如何釋放呢?
最簡單的就是使用 swap()交換函數(shù),使vector離開其自身的作用域,從而強(qiáng)制釋放vector所占的內(nèi)存空間。
template < class T >
void ClearVector( vector< T >& vt )
{
vector< T > vtTemp;
veTemp.swap( vt );
}一般的STL內(nèi)存管理器allocator都是用內(nèi)存池來管理內(nèi)存的,所以某個(gè)容器申請(qǐng)內(nèi)存或釋放內(nèi)存都只是影響到內(nèi)存池的剩余內(nèi)存量,而不是真的把內(nèi)存歸還給系統(tǒng)。
這樣做一是為了避免內(nèi)存碎片,二是提高了內(nèi)存申請(qǐng)和釋放的效率。
事實(shí)上,vector容器在內(nèi)存不夠時(shí)就向內(nèi)存管理框架申請(qǐng)內(nèi)存,內(nèi)存管理框架如果發(fā)現(xiàn)內(nèi)存不夠了,就malloc內(nèi)存,但是當(dāng)vector釋放資源的時(shí)候(比如destruct), stl根本就不調(diào)用free以減少內(nèi)存,因?yàn)閮?nèi)存分配在stl的底層:stl假定如果你需要更多的資源就代表你以后也可能需要這么多資源(你的list, hashmap也是用這些內(nèi)存),所以就沒必要不停地malloc/free。
注意:這邊說到的是系統(tǒng)分配的內(nèi)存的申請(qǐng)/釋放。如果vector中存放的是指針,那么當(dāng)vector銷毀時(shí),這些指針指向的對(duì)象不會(huì)被銷毀,那么內(nèi)存就不會(huì)被釋放。開發(fā)者自己申請(qǐng)的內(nèi)存記得自己釋放。
C++容器vector內(nèi)存釋放問題
突然遇到vector在使用clear之后,其內(nèi)存(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;?輸出結(jié)果:
0
1 3 3
1
1 0 3
0 3
可以發(fā)現(xiàn),在使用clear之后,size和empty改變了,但是capacity依舊是那么大(總算是理解C++Primer:vector在生命周期內(nèi),內(nèi)存大小是只增不減)。
這里提供兩種釋放方法
第一種:
作用域+臨時(shí)變量+swap函數(shù):swap函數(shù)可以直接交換容器的內(nèi)存
? ? {
? ? ? ? std::vector<int>().swap(v1); ?
? ? }
? ? cout << v1.size() << " " << v1.capacity() << endl;運(yùn)行結(jié)果:
0 0
第二種:
不易發(fā)現(xiàn)的成員函數(shù):shrink_to_fit去釋放。
? ? v1.shrink_to_fit(); ? ? cout << v1.size() << " " << v1.capacity() << endl;?
運(yùn)行結(jié)果:
0 0
但是,雖然clear之后vector的內(nèi)存不會(huì)釋放,但是重新emplace_back之后的數(shù)據(jù),會(huì)從容器內(nèi)存起始地址開始重新存放。
總結(jié)
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
C++基于socket編程實(shí)現(xiàn)聊天室功能
這篇文章主要介紹了C++基于socket編程實(shí)現(xiàn)聊天室功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-07-07
C++中用棧來判斷括號(hào)字符串匹配問題的實(shí)現(xiàn)方法
這篇文章主要介紹了C++中用棧來判斷括號(hào)字符串匹配問題的實(shí)現(xiàn)方法,是一個(gè)比較實(shí)用的算法技巧,包含了關(guān)于棧的基本操作,需要的朋友可以參考下2014-08-08
C++基于Floyd算法實(shí)現(xiàn)校園導(dǎo)航系統(tǒng)
這篇文章主要為大家詳細(xì)介紹了C++基于Floyd算法實(shí)現(xiàn)校園導(dǎo)航系統(tǒng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-03-03
C++實(shí)現(xiàn)LeetCode(191.位1的個(gè)數(shù))
這篇文章主要介紹了C++實(shí)現(xiàn)LeetCode(191.位1的個(gè)數(shù)),本篇文章通過簡要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下2021-08-08
C語言十進(jìn)制轉(zhuǎn)二進(jìn)制代碼實(shí)例
這篇文章主要介紹了C語言十進(jìn)制轉(zhuǎn)二進(jìn)制代碼實(shí)例,并且轉(zhuǎn)換后會(huì)統(tǒng)計(jì)二進(jìn)制1的個(gè)數(shù),實(shí)例簡單明了,需要的朋友可以參考下2014-06-06

