簡體   English   中英

在c ++中使用realloc

[英]Using realloc in c++

如果malloc內存包含非pod類型,則std::realloc在c ++中是危險的。 似乎唯一的問題是,如果std::realloc無法在原位增長內存,則不會調用類型析構函數。

一個簡單的工作是try_realloc函數。 如果它不能在原地生長,而不是malloc'ing新的記憶,它將簡單地返回false。 在這種情況下,可以分配新內存,將對象復制(或移動)到新內存,最后釋放舊內存。

這看起來非常有用。 std::vector可以很好地利用它,可能避免所有的副本/重新分配。
搶先阻燃:從技術上講,這與Big-O性能相同,但如果矢量增長是您應用中的瓶頸,即使Big-O保持不變,x2加速也很好。

但是,我找不到任何像try_realloc一樣工作的c api。

我錯過了什么嗎? try_realloc沒有我想象的那么有用嗎? 是否有一些隱藏的錯誤使try_realloc無法使用?

更好的是,是否有一些記錄較少的API執行類似try_realloc

注意:我很明顯,在這里的庫/平台特定代碼中。 我並不擔心,因為try_realloc本身就是一種優化。


更新:繼Steve Jessops評論使用realloc是否更有效的vector我寫了一個概念驗證來測試。 realloc-vector模擬向量的增長模式,但可以選擇重新分配。 我在程序中運行了一百萬個元素。

為了比較, vector必須分配19次,同時增長到一百萬個元素。

結果,如果realloc-vector是唯一使用堆的結果是很棒的,3-4分配同時增長到百萬字節的大小。

如果realloc-vector與一個生長速度為66%的vector一起使用,那么realloc-vector的速度就不那么有希望了,在生長期間分配8-10次。

最后,如果realloc-vector與以相同速率增長的vector一起使用,則realloc-vector分配17-18次。 在標准向量行為上僅保留一個分配。

我不懷疑黑客可以通過游戲分配大小來提高節省,但我同意Steve的觀點,即編寫和維護這樣一個分配器所付出的巨大努力並不適用於此。

vector通常以大增量增長。 除非你仔細安排事情,以便在向量的內部緩沖區之上存在大量的空閑地址(實際上需要分配整個頁面,因為顯然你不能進行其他分配,否則你不能在沒有重新定位的情況下重復這樣做。稍后在同一頁面上)。

所以我認為,為了在這里獲得一個非常好的優化,你需要的不僅僅是一個“瑣碎的解決方法”,如果可能的話,可以進行廉價的重新分配 - 你必須以某種方式做一些准備才能使它成為可能,並且准備成本會讓你解決空間問題。 如果你只針對某些向量,那些表明它們會變大的向量,那么它就毫無意義,因為它們可以用reserve()表示它們會變大。 如果你有一個巨大的地址空間,你只能為所有向量自動執行它,這樣你就可以在每個向量上“浪費”它的大部分。

據我了解, Allocator概念沒有重新分配功能的原因是為了保持簡單。 如果std::allocator有一個try_realloc函數,那么每個Allocator都必須有一個(在大多數情況下無法實現,並且只需要總是返回false),否則每個標准容器都必須是專用的為std::allocator利用它。 這兩個選項都不是一個很好的Allocator接口,盡管我認為對於幾乎所有Allocator類的實現者而言,添加一個do-nothing try_realloc函數並不是一項巨大的努力。

如果由於重新分配導致vector緩慢,則deque可能是一個很好的替代品。

你可以實現類似的try_realloc你建議,使用mmapMAP_ANONYMOUSMAP_FIXEDmremapMREMAP_FIXED

編輯 :剛剛注意到mremap的手冊頁甚至說:

mremap()使用Linux頁表方案。 mremap()更改虛擬地址和內存頁面之間的映射。 這可用於實現非常有效的realloc(3)。

C中的realloc幾乎不是一個便利函數; 它對性能/減少副本幾乎沒有好處。 我能想到的主要異常是分配一個大數組然后在知道所需大小后縮小大小的代碼 - 但即使這可能需要在一些malloc實現上移動數據(嚴格按大小隔離塊的數據)所以我考慮這個用法realloc非常糟糕的做法。

只要每次添加元素時都不經常重新分配數組,而是在空間不足時以指數方式(例如,25%,50%或100%)增加數組,只需手動分配新內存,復制和釋放舊的將產生與使用realloc大致相同(並且在內存碎片情況下相同)的性能。 這肯定是C ++ STL實現使用的方法,所以我認為你的整個關注是沒有根據的。

編輯realloc實際上有用的一個(罕見但不是聞所未聞)的情況是具有虛擬內存的系統上的巨型塊,其中C庫與內核交互以將整個頁面重新定位到新地址。 我說這種情況很少見的原因是因為在大多數實現甚至進入處理頁面粒度分配的領域之前你需要處理非常大的塊(至少幾百kB),並且可能要大得多(可能有幾MB)在進入和退出內核空間以重新排列虛擬內存之前,比簡單地進行復制要便宜。 當然try_realloc在這里try_realloc ,因為整個好處來自於實際上低成本進行移動

暫無
暫無

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

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