1. 程式人生 > >SGI STL內存配置器存在內存泄漏嗎?

SGI STL內存配置器存在內存泄漏嗎?

析構 溫故而知新 溫故 由於 默認 文件路徑 htm .com 成員

閱讀了SGI的源碼後對STL很是膜拜,很高質量的源碼,從中學到了很多。溫故而知新!下文中所有STL如無特殊說明均指SGI版本實現。

STL 內存配置器

STL對內存管理最核心部分我覺得是其將C++對象創建過程分解為構造、析構和內存分配、釋放兩類操作分離開來!擺脫了對頻繁調用new或malloc函數想操作系統申請空間而造成的低效。其中析構操作時對具有non-trival、trival 析構函數的class區別對待也提高了效率。SGI 的兩級配置器結構屬於錦上添花。

STL內存配置器有沒有內存泄漏?

STL兩級結構的配置器使得STl能對小的空間內存分配管理更為合理,而很多人有疑問的時這個對小空間的配置器是否存在內存泄漏?“源碼面前了無秘密”問題來於源碼自,答案也在源碼之中。先概述一下STL兩級結構的配置器是怎麽操作的,STL的Allocator中隊內存的申請和釋放均是通過其兩個靜態成員函數完成,allocate,deallocate;對於大於128Byte的內存申請和釋放,兩個函數均通過調用malloc和free來實現。當內存不大於138Byte時,該allocator會通過一個鏈表和內存池來維護空間。很多人疑惑為什麽在該Allocator的實現裏只有對內存池malloc的代碼,沒看到類似free這樣釋放內存的代碼,甚至該Allocator類都沒有析構函數,這樣不是會存在內存泄漏嗎?其實不然,對於由鏈表維護的內存,其內存的釋放工作應該是上一層調用者負責,比如容器Vector在析構函數中就顯示的將其申請的所有capacity大小的內存釋放。內存池則不一樣,內存池的中的內存將會一直保留知道程序退出。有的同學可能會認為“這不就是內存泄漏嗎?比如一個創建了一個Vector變量,到Vector析構了之後再內存中竟然有一塊內存沒有被系統回收,這不就是內存泄漏嗎”,其實不然:

1. 申請的內存沒有被及時釋放不等於內存泄漏

在單線程中,由於該Allocator中記錄內存池起始的指針是靜態類型,所以只要是你在同一個線程中,無論你創建多少個Allocator,記錄內存池的變量都是同一個,換句話說,當下次再創建Vector時,還是使用上一次使用的那個。

2. 該內存池不會瘋狂野生長

這個內存池的空間其實是很小的,因為大於128Byte的內存申請都直接轉調了malloc,從源碼中也可以看出,內存池每次重新灌水的新容量是2*total_size + round_up(heap_size >> 4)。

內存池的存在是為了避免大量內存碎片的產生,代價是管理內存所需要多付出的時間和空間消耗。

以上就是內存池一種存在直至程序退出的原因。

在GCC 5.4.0 中的使用的SGI已經對該種設計做了大幅修改。1. 默認的Allocator也不在是侯捷一書中說指出的具有內存池的配置器,而是"\usr\include\c++\5\ext\new_allocator.h"其實現直接調用new;2. 而之前相應的具備內存池的配置器則被當做STL的擴展,實現於"\usr\include\c++\5\ext\pool_allocator.h"中,且該實現不在存在內存池的設計,只保留了使用鏈表將小內存塊連接起來的設計(使用時記得include該文件路徑,命名空間為__gnu_cxx::__pool_alloc<int> )。

在llvm中Allocator的實現也是直接調用new。

FYI:

GCC更換Allocator設計,http://www.cppblog.com/peakflys/archive/2015/01/14/209513.html

SGI源碼,https://www.sgi.com/tech/stl/download.html

SGI源碼,allocator,https://www.sgi.com/tech/stl/stl_alloc.h

SGI源碼,vector,https://www.sgi.com/tech/stl/stl_vector.h

SGI STL內存配置器存在內存泄漏嗎?