[英]How to get the heap memory allocated to each generation (Gen0,Gen1,Gen2)?
[英]Why are gen1/gen2 collections slower than gen0?
根據我的軼事知識,就 GC 而言,創建短期對象並不太麻煩——這意味着 gen0 集合非常快。 然而,Gen1/gen2 集合似乎更“可怕”,即據說通常比 gen0 慢很多。
這是為什么? 是什么讓 gen2 收集平均比 gen0 慢得多?
我不知道集合方法本身之間有任何結構差異(即在標記/清除/壓縮階段完成的事情),我是否遺漏了什么? 或者僅僅是因為例如 gen2 往往大於 gen0,因此需要檢查更多的對象?
為了放大 canton7 的回答,有必要注意一些額外的事情,其中之一增加了所有集合(尤其是 gen1 和 gen2)的成本,但降低了它們之間的分配成本,其中一個降低了 gen0 的成本和 gen1 集合:
許多垃圾收集器的行為有點類似於清理建築物,將所有有價值的東西轉移到另一棟建築物,炸毀原有建築物並重建空殼。 將事物從 gen0 建築物移動到 gen1 建築物的 gen0 集合將相當快,因為 gen0“建築物”中不會有太多東西。 一個 gen2 集合必須移動更大的 gen2 建築物中的所有東西。 垃圾收集系統可以為較小的 gen2 對象和較大的對象使用單獨的建築物,並通過跟蹤自由空間的各個區域來管理較大的建築物,但是移動較小的對象和回收批發存儲比嘗試管理所有單獨的存儲區域要少這將有資格重新使用。 然而,這里要觀察的一個關鍵點是,即使有必要掃描 gen1 或 gen2 對象,也沒有必要移動它,因為它所在的“建築物”不是立即拆除的目標。
許多系統使用“卡片表”,它可以記錄自上次 gen0 或 gen1 集合以來每個 4K 內存塊是否已被寫入,或包含用於修改對象的引用。 這會顯着減慢對任何此類存儲區域的首次寫入速度,但在 gen0 和 gen1 集合期間,可以跳過對大量對象的檢查。 卡片表的使用細節各不相同,但基本概念是,如果代碼有大量引用,但大部分都落在未標記的 4K 塊內,GC 甚至無需查看這些塊就可以知道那這將是通過訪問他們的任何新的對象也將是其他方式訪問,因此將有可能找到所有GEN0對象,而不會打擾在所有這些塊的樣子。
請注意,即使沒有卡片表的簡單垃圾收集系統也可以簡單輕松地受益於分代 GC 的原理。 例如,在 Commodore 64 BASIC 上,它的垃圾收集器非常慢,一個創建了大量長壽命字符串的程序可以通過使用幾個 peek 和 poke 語句來調整字符串的頂部,從而避免冗長的垃圾收集周期——堆指針位於長期存在的字符串底部的正下方,因此它們不會被考慮用於重定位/回收。 如果一個程序使用數百個將在整個程序執行過程中持續存在的字符串(例如一個從 00 到 FF 的兩位十六進制字符串表),以及一些其他字符串,這可能會將垃圾收集時間減少一個數量級以上震級。
想到的幾個原因:
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.