一般的malloc實現,對一塊已分配的記憶體,都有兩個機器字的簿記,甚至更多。如果不需要排錯,理論上講,只需要乙個字長的額外開銷,用來記錄這塊記憶體的尺寸(放在intptr[-1]處是個好主意)。
為什麼需要這個開銷呢?因為free傳入的只是個指標,它不知道要釋放多大的記憶體,因此free內部必須通過某種方式來獲得這塊記憶體的尺寸。
可以想象,如果用 malloc/free 來作為乙個關聯陣列(map)的分配器,要浪費不少記憶體。不過好在實際資料的尺寸往往比額外消耗要大很多,相比起來,浪費的比例不算很大,況且現在記憶體還很便宜。
其實,打造乙個高效的分配器並不難,難的是它的適用範圍(多執行緒?cell尺寸,chunk尺寸,對齊,排錯...),如果可以忍受這些缺陷,或者說是限制,還是比較值得的。下一步就是它的靈活性——讓它可以更加容易整合進其它系統。
對於c標準庫,如果能增加乙個/一族這樣的分配器,還是很有價值的。從理論上講,只要free時多傳乙個size引數,就可以完全去掉額外的開銷。這樣兩個函式就可以做到:
void* salloc(size_t size); void sfree(void* ptr, size_t size);
這樣做還有乙個額外的好處,就是可以更好地對齊,假定程式需要按32位元組對齊,malloc/free 就至少需要32位元組做簿記,如果再加上記憶體越界檢測,就需要64位元組。salloc/sfree則只需要將分配的記憶體對齊到32位元組邊界即可。
但是這對程式的正確性要求很高,malloc/free中,記憶體越界檢測可以很容易實現,而salloc/sfree就完全做不到(除非增加額外簿記)。乙個好主意是可以在debug版中加入這些差錯功能,而在release版中去掉。
更好(確切地講應該是更靈活)的方案是,實現乙個
struct mpool; // return success or fail int mpool_init(struct mpool* pool); void mpool_destroy(struct mpool* pool); void* mpalloc(struct mpool* pool, size_t size); void mpfree(struct mpool* pool, void* ptr, size_t size);
而讓 salloc/sfree簡單地作為 mpool 的包裝。
gcc的std::allocator基本上是按這樣的方式實現的,只不過,它的size引數,大多數時刻是自動傳遞的(知道具體的class/struct,也就知道它的尺寸)。實現方式上,使用 size_aligned/align 作為索引去訪問特定尺寸的mempool,乙個 mempool 是多個鍊錶串起來的大chunk,每個chunk內部是鍊錶穿起來的cell。這也許是最好的實現方式了,除了節省的額外空間開銷,時間開銷上,如果不考慮加鎖,一次alloc平均可以在10時鐘週期內完成,dealloc用的時間更短。相比之下malloc/free耗的時間也要多得多。
malloc free 的開銷,如何去掉這種開銷?
一般的malloc實現,對一塊已分配的記憶體,都有兩個機器字的簿記,甚至更多。如果不需要排錯,理論上講,只需要乙個字長的額外開銷,用來記錄這塊記憶體的尺寸 放在intptr 1 處是個好主意 為什麼需要這個開銷呢?因為free傳入的只是個指標,它不知道要釋放多大的記憶體,因此free內部必須通過某種...
如何處理I O開銷
如何成為優秀程式設計師第 9 100 期分享 閱讀本文大概需要 2 分鐘 01 構建乙個快速的系統通常是乙個提高 i o 在很多問題上,處理器的速度比硬體交流要快得多。這種代價通常是小的 i o,可能包括網路消耗,磁碟 i o,資料庫查詢,檔案 i o,還有其他與處理器不太接近的硬體使用。所以構建乙...
Trace 如何跟蹤某個Job的開銷
下面是從以往profiler收集的跟蹤檔案中提取job有關資料 with cte as select b.name eventclass,textdata,databasename,duration 1000 duration ms row number by cpu desc rankid fro...