3 回答

TA貢獻1836條經(jīng)驗 獲得超4個贊
是的,他們就是這么說的。
在 64 位架構(gòu)上(目前)不需要拆分堆棧,因為 64 位虛擬地址空間非常大,可以包含數(shù)百萬個堆棧地址范圍,如果需要,每個地址范圍都相當于整個 32 位地址空間。
在當今使用的平面內(nèi)存模型中,從虛擬地址到物理內(nèi)存位置的轉(zhuǎn)換是在硬件 MMU的支持下完成的。在amd64 上,事實證明將 64 位虛擬地址空間的大塊保留給您正在創(chuàng)建的每個新堆棧會更好(意味著總體上更快),而只將第一頁 (4kB) 映射到實際 RAM。這樣,堆棧將能夠根據(jù)需要在連續(xù)的虛擬地址上增長和縮?。ㄒ馕吨總€函數(shù)序言中的代碼更少,一個很大的優(yōu)化),而操作系統(tǒng)重新配置 MMU 以將虛擬地址的每個頁面映射到實際RAM 的空閑頁面,每當堆棧增長或縮小到高于/低于某些可配置閾值時。
通過巧妙地選擇閾值(例如參見動態(tài)數(shù)組理論),您可以在平均堆棧操作上實現(xiàn) O(1) 復(fù)雜度,同時保留數(shù)百萬堆棧的好處,這些堆??梢愿鶕?jù)需要增長并且只消耗內(nèi)存他們使用。
PS:當前的 Go 實現(xiàn)遠遠落后于此:-)

TA貢獻1848條經(jīng)驗 獲得超10個贊
更新 Go 1.4(2014 年第四季度)
更改為運行時:
在 Go 1.4 之前,運行時(垃圾收集器、并發(fā)支持、接口管理、映射、切片、字符串等)主要是用 C 編寫的,有一些匯編器支持。
在 1.4 中,大部分代碼已轉(zhuǎn)換為 Go,以便垃圾收集器可以在運行時掃描程序堆棧并獲取有關(guān)哪些變量處于活動狀態(tài)的準確信息。
這種重寫使 1.4 中的垃圾收集器完全精確,這意味著它知道程序中所有活動指針的位置。這意味著堆會更小,因為不會有誤報使非指針保持活動狀態(tài)。其他相關(guān)更改也減少了堆大小,與之前的版本相比,總體上減少了 10%-30%。
結(jié)果是堆棧不再分段,消除了“熱拆分”問題。當達到堆棧限制時,會分配一個新的更大的堆棧,goroutine 的所有活動幀都被復(fù)制到那里,并且所有指向堆棧的指針都會被更新。
初步答復(fù)(2014 年 3 月)
Agis Anastasopoulo的文章“ Go中的連續(xù)堆棧”也解決了這個問題
在堆棧邊界碰巧陷入緊密循環(huán)的情況下,重復(fù)創(chuàng)建和銷毀段的開銷變得很大。
這在 Go 社區(qū)內(nèi)部被稱為“熱分裂”問題。
“熱拆分”將在 Go 1.3 中通過實現(xiàn)連續(xù)堆棧來解決。
現(xiàn)在,當堆棧需要增長時,會發(fā)生以下情況,而不是分配新段:
創(chuàng)建一個新的、更大的堆棧
將舊堆棧的內(nèi)容復(fù)制到新堆棧
重新調(diào)整每個復(fù)制的指針以指向新地址
銷毀舊堆棧
下面提到一個主要出現(xiàn)在 32 位架構(gòu)中的問題:
不過也有一定的挑戰(zhàn)。
1.2 運行時不知道堆棧中指針大小的字是否為實際指針??赡苡懈↑c數(shù)和最罕見的整數(shù),如果解釋為指針,實際上會指向數(shù)據(jù)。
由于缺乏此類知識,垃圾收集器必須保守地將堆棧幀中的所有位置視為根。這留下了內(nèi)存泄漏的可能性,尤其是在 32 位體系結(jié)構(gòu)上,因為它們的地址池要小得多。
然而,在復(fù)制堆棧時,必須避免這種情況,并且在重新調(diào)整時只應(yīng)考慮真正的指針。
工作已經(jīng)完成,關(guān)于實時堆棧指針的信息現(xiàn)在嵌入在二進制文件中,可供運行時使用。
這意味著不僅 1.3 中的收集器可以精確地堆疊數(shù)據(jù),而且現(xiàn)在可以重新調(diào)整堆棧指針。
- 3 回答
- 0 關(guān)注
- 237 瀏覽
添加回答
舉報