簡體   English   中英

有效地使用多個分配器

[英]Using multiple allocators efficiently

我一直在研究切換我的分配方法,從簡化重載新到通過代碼庫使用多個分配器。 但是,如何有效地使用多個分配器? 我可以通過我的研究設計的唯一方法是讓分配器成為全局變量。 雖然,這似乎有問題,因為使用許多全局變量通常是一個“壞主意”。

我想找到如何有效地使用多個分配器。 例如,我可能只有一個分配器用於特定子系統,而另一個分配器用於不同的子系統。 我不確定這樣做的唯一方法是使用多個全局分配器,所以我希望有更好的洞察力和設計。

在C ++ 2003中,分配器模型被破壞,並沒有真正適當的解決方案。 對於C ++ 2011,分配器模型是固定的,您可以將每個實例分配器傳播到包含的對象(當然,除非您選擇替換它們)。 通常,為了使它有用,你可能想要使用一個動態多態分配器類型,默認的std::allocator<T>不是必需的(通常我會期望它不是動態多態的,盡管這可能是更好的實施選擇)。 但是,[幾乎]標准C ++庫中進行內存分配的所有類都是將分配器類型作為模板參數的模板(例如,IOStream是一個例外,但通常它們不會分配任何有意義的內存量來保證添加分配器支持)。

在您的一些評論中,您堅持認為分配器實際上需要是全局的:這絕對不正確。 每個分配器識別類型存儲給定的分配器的副本(至少,如果它具有任何實例級數據;如果它沒有,則沒有任何東西要存儲,例如使用operator new()的默認分配器的情況和operator delete() )。 這實際上意味着只要存在使用它的任何活動分配器,給予對象的分配機制就需要保持不變。 可以使用全局對象來完成,但也可以使用例如引用計數或將分配器與包含給定它的所有對象的對象相關聯來完成。 例如,如果每個“文檔”(想想XML,Excel,Pages,無論結構文件)都將分配器傳遞給其成員,那么分配器可以作為文檔的成員存活,並在文檔被銷毀后銷毀所有內容后銷毀。 分配器模型的這一部分應該與C ++之前的2011類一起使用,只要它們也使用allocator參數。 但是,在C ++ 2011之前的類中,分配器不會傳遞給包含的對象。 例如,如果你給一個std::vector<std::string>的分配器,那么C ++ 2011版本將使用給定給std::vector<std::string>的分配器來創建std::string 。適當轉換為處理std::string s。 使用pre-C ++ 2011分配器不會發生這種情況。

要在子系統中實際使用分配器,您實際上需要傳遞它們,或者顯式地作為函數和/或類的參數,或者通過作為上下文的分配器感知對象隱式地傳遞它們。 例如,如果您使用任何標准容器作為傳遞的上下文的[部分],則可以使用其get_allocator()方法獲取已使用的分配器。

您可以使用new展示位置。 這可以用於指定內存區域,也可以用於重載類型的static void* operator new(ARGS) 如果效率很重要且問題很嚴重,那么全球不是必需的,而且這里真的是個壞主意。 當然,您需要保留一個或多個分配器。

您可以做的最好的事情是了解您的問題,並根據程序中的模式和實際使用情況為您的分配器創建策略。 通用malloc非常擅長它的功能,所以總是將它作為一個基線進行衡量。 如果您不知道您的使用模式,您的分配器可能會比malloc慢。

還要記住,您使用的這些類型將失去與標准容器的兼容性,除非您為標准容器使用全局或線程本地和自定義分配器 - 這在很多情況下很快就會失敗。 另一種方法是編寫自己的分配器和容器。

多個分配器的一些用途包括減少CPU使用,減少碎片和減少緩存未命中。 因此,解決方案實際上取決於您的分配瓶頸的類型和位置。

通過為活動線程提供無鎖堆,消除同步,可以提高CPU使用率。 這可以在具有線程本地存儲的內存分配器中完成。

通過從不同堆分配不同生命周期的分配來改進碎片 - 在用戶活動任務的單獨堆中分配后台IO將確保兩者不會相互混淆。 這可能是通過堆積堆棧來實現的,並且當您處於不同的功能范圍時推送/彈出。

通過將系統內的分配保持在一起,可以改善緩存未命中。 讓Quadtree / Octree分配來自他們自己的堆將保證在視圖frustrum查詢中存在位置。 最好通過重載特定類(OctreeNode)的operator new和operator delete來完成。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM