data Car = Car { carName :: String, carFunctionality :: ByteString }
main :: IO ()
main = do
complexFunctionality <- undefined -- create complex functionality
let myCar = Car {
carName = "myCar",
carFunctionality = complexFunctionality }
-- A) Call functions that use myCar, but only use carName.
-- They don't use the carFunctionality.
-- B) From here on, myCar is never again used.
問題:
一旦達到 B),垃圾收集器(下次觸發時)會收集
myCar嗎?我可以自己回答這個問題。答案顯然是肯定的,因為這就是 GC 的重點。更重要的問題。在 A) 中的函式呼叫期間,是否存在
complexFunctionality因為無處使用而被收集的風險?換句話說,我想知道是否有可能complexFunctionality在收集周圍物件之前收集物件 ()myCar。您在 2. 中的答案是否可靠,即它是否面向未來(Haskell 的行為有據可查,而不僅僅是當前 GHC 的一個偶然特性)?
uj5u.com熱心網友回復:
您從“風險”的角度談論問題 2。這是一個奇怪的措辭選擇:這種 GC 行為會如何對您產生負面影響?實際上,GHC 可能不會收集您的子物件。原則上,一個足夠聰明的 GC 可能會這樣做,如果它對您的程式的行為有足夠的了解,例如通過行內。垃圾收集的重點是它只發生在您不會再次使用的物件上。如果您不再使用它們,為什么收集它們會有“風險”?相反,大多數人會認為這是一種好處!這個過時的物件可以盡早收集,為當前更重要的物件釋放記憶體。因此,我再次建議您多考慮一下為什么您認為這是一種風險:如果您認為它很危險,那么您的假設或您的程式可能已經被破壞了。
uj5u.com熱心網友回復:
(2) 的簡單答案是“否”。GHC 的垃圾收集器被設計成如果一個多欄位值被標記為“已使用”,它的所有欄位(它的“內部物件”)也被標記為“已使用”。正如@amalloy 指出的那樣,這不一定是一件好事。如果一個未使用的物件可以被垃圾收集,即使它是某個已使用物件的欄位,它可能會更好。然而,設計一個垃圾收集器來做到這一點很困難,而且幾乎沒有意義(我稍后會解釋),這也有助于回答(3):是的,幾乎可以保證 GHC 垃圾收集器永遠不會被重新設計為收集“內部物件”來自使用中的“外部物件”。
設計垃圾收集器來收集已用物件的未使用欄位的原因是毫無意義的,因為這可以在編譯期間通過應用適當的優化來更好地完成。考慮以下程式:
import Data.ByteString (ByteString)
import qualified Data.ByteString as BS
data Car = Car { carName :: String, carFunctionality :: ByteString }
main :: IO ()
main = do
complexFunctionality <- BS.readFile "/etc/passwd"
let myCar = Car {
carName = "myCar",
carFunctionality = complexFunctionality }
print $ carName myCar
print "done with myCar"
如果您使用優化編譯它并轉儲優化的代碼,請使用:
ghc -O2 Example1.hs -fforce-recomp -ddump-simpl -dsuppress-all -dsuppress-uniques
生成的優化代碼(誠然難以閱讀)相當于:
main = do
BS.readFile "/etc/passwd"
print "myCar"
print "done with myCar"
(事實上??,如果你編譯這個版本,得到的優化代碼與原始的優化代碼完全相同main。)
GHC 不會優化掉readFile自身,因為它是一個 I/O 操作,而且 GHC 不會優化掉 I/O 操作,即使它們“顯然”沒有效果。但是,結果readFile被忽略了,這意味著——實際上——carProperties ByteString可以在readFile陳述句之后立即進行垃圾收集。就此而言,Car物件被完全優化掉,因此它永遠不會被創建,更少的垃圾收集。
So, the bottom line is that compile-time optimizations can usually realize most of the benefits of "inner object garbage collection" by eliminating the dependency of an "outer object" on an "inner object" in the first place, which means that the garbage collector itself doesn't need any special functionality to identify and collect "inner objects", as they'll naturally be collected as unused objects in the optimized code.
uj5u.com熱心網友回復:
在某些情況下,GHC 的 GC 演算法中的優化可能會導致它收集資料型別中未使用的欄位。 堆物件檔案的這一部分描述了一種堆物件型別,即選擇器 thunk,它是從特定代碼創建的,專門用于啟用此優化。
為任何形式的函式生成選擇器 thunk \x -> case x of Pat n1 n2 n3 ... -> nk。IE,一個匹配單個建構式并從中回傳一個欄位的函式。當垃圾收集器遇到應用于某個值的選擇器 thunk 時,它會向前看。如果該值已被評估并與預期的建構式匹配,它將重寫 thunk 以直接參考該欄位,洗掉對包含資料值的參考。如果從 GC 根不再可以訪問包含的值,則該值將被遺忘,并將被垃圾收集器連同它包含的任何不再可訪問的內容一起收集。
此程序可能導致收集未使用的記錄欄位的情況,而您仍可能認為當前狀態是整個記錄被未評估的運算式關閉。但這既是一種罕見的情況,你需要一個稍微復雜的心智模型來了解懶惰是如何運作的,甚至可以識別出懶惰表示它可能在記憶中保留了不必要的內容。
轉載請註明出處,本文鏈接:https://www.uj5u.com/qukuanlian/423017.html
標籤:
