GC的壓縮,掃描和標記避免了堆內存碎片。那麼在Swift中如何避免內存碎片?Swift中如何避免內存碎片
這些陳述是否正確?
- 每當引用計數變爲零時,分配的空間就會被添加到「可用」列表中。
- 對於下一個分配,可以使用適合大小的最前面的內存塊。先前使用的內存
- 大塊將再次曾經是最好儘可能
是通過地址位置或大小排序的「可用列表」?
爲了更好的壓實,活物是否會移動?
GC的壓縮,掃描和標記避免了堆內存碎片。那麼在Swift中如何避免內存碎片?Swift中如何避免內存碎片
這些陳述是否正確?
是通過地址位置或大小排序的「可用列表」?
爲了更好的壓實,活物是否會移動?
我做了一些編譯Swift程序的彙編,我發現swift:: swift_allocObject
是一個新的Class對象實例化時調用的運行時函數。它調用SWIFT_RT_ENTRY_IMPL(swift_allocObject)
,它調用swift::swift_slowAlloc
,最終調用C標準庫中的... malloc()
。所以Swift的運行時沒有執行內存分配,它是malloc()
。
malloc()
在C庫(libc
)中實現。你可以看到蘋果的執行libc
here。 malloc()
定義於/gen/malloc.c
。如果您對使用哪種內存分配算法感興趣,則可以繼續從那裏的 下拉兔子洞。
'可用列表'是按地址位置還是大小排序?
這是一個malloc
的實現細節,我歡迎您在上面鏈接的源代碼中發現。
1.每當引用計數變爲零時,分配的空間就會被添加到「可用」列表中。
是的,這是正確的。除了「可用」列表可能不是一個列表。此外,此操作不一定由Swift運行時庫完成,但可以通過系統調用由OS內核完成。
2.對於下一個分配,可以使用適合大小的最前面的內存塊。
不一定是最前面的。有許多不同的內存分配方案。你想到的那個叫做「第一個適合」。以下是一些示例性的存儲器分配技術(來自this site):
最佳擬合:分配器放置一個過程中未分配存儲器將在其中適合的最小的塊。例如,假設一個進程請求12KB內存,並且內存管理器當前有一個6KB,14KB,19KB,11KB和13KB塊的未分配塊列表。最合適的策略是將12KB的13KB塊分配給進程。
首先擬合:有可能是在存儲器的許多孔,因此操作系統,以減少它花費分析可用空間的時間量,從第一開始於主存儲器的起始和分配內存它遇到足夠大的孔以滿足要求。使用與上面相同的示例,首次擬合將爲進程分配12KB的14KB塊。
- 最壞情況:內存管理器將進程放入可用的最大未分配內存塊中。我們的想法是,這種佈局會在分配之後創建最大的保留位置,從而增加與最佳匹配相比,另一個進程可以使用剩餘空間的可能性。使用與上述相同的示例,最差配合將爲該進程分配12KB的19KB塊,留下7KB塊供將來使用。
對象在使用期限內不會被壓縮。 libc
通過分配內存的方式處理內存碎片。它無法移動已分配的對象。
亞歷山大的回答是偉大的,但也有一定的相關性內存佈局一些其他細節。垃圾收集需要用於壓縮的內存開銷,所以從malloc碎片中浪費的空間實際上並沒有使它處於劣勢。移動內存也會對電池和性能產生影響,因爲它會使處理器緩存無效。 Apple的內存管理實現可以壓縮一段時間內尚未訪問的內存。儘管虛擬地址空間可以被分割,但實際的RAM由於壓縮而不易碎化。壓縮還允許更快地交換到磁盤。
較少有關,但大的原因,蘋果採摘引用計數更多的是與c-調用,那麼內存佈局之一。如果您與c-libraries大量交互,Apple的解決方案效果會更好。垃圾收集系統通常與c進行交互的速度級別較低,因爲它需要在調用之前暫停垃圾收集操作。開銷通常與任何語言的系統調用大致相同。通常情況下,除非您在循環中調用c函數,例如使用OpenGL或SQLite,這並不重要。其他線程/進程通常可以使用處理器資源,而c調用正在等待垃圾收集器,所以如果您可以在幾個調用中完成工作,影響最小。在未來,當涉及到系統編程和類似生鏽的生命週期內存管理時,Swift的內存管理可能會有優勢。它在Swift的路線圖上,但Swift 4還不適合系統編程。通常在C#中,您可以使用託管C++來進行大量使用c庫的系統編程和操作。