以 WinForms 圖形化模擬 GC 核心概念:物件配置、代系晋升、根可達性判斷、Finalize 队列、Freachable 队列、記憶體不足觸發完整收集。非真實 CLR 實作,僅供教學視覺化。
newobj → 計算大小 → 檢查 Gen0 空間 → 足夠則配置,否則觸發 GC~Class(),不可控執行時機,GC.Collect()、Gen0 滿、記憶體不足、AppDomain 卸載、CLR 關閉時觸發IDisposable,決定釋放,可配合 HandleCollector 誘發 GC// 物件實體
public class DataObject {
public bool HasFinalizeMethod { get; set; }
public bool HasRoot { get; set; }
public int Size { get; set; } // 模擬記憶體大小 (1~3 單位)
public Color Color { get; set; } // 視覺化顏色
public string Name { get; set; } // GUID
public int Generation { get; set; } // 0/1/2
public string Tag => HasFinalizeMethod ? "[F]" : "[!F]";
}
// 物件集合
public class DataObjects : IEnumerable<DataObject> {
List<DataObject> list = new List<DataObject>();
public void Add(DataObject o) { if (!list.Contains(o)) list.Add(o); }
public void Remove(DataObject o) { list.Remove(o); }
public int Count => list.Count;
public DataObject this[int i] => list[i];
public IEnumerator<DataObject> GetEnumerator() => list.GetEnumerator();
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
}
// 管理器:全域集合 + 三代視圖 + Finalize/Freachable 隊列
public class DataObjectManager {
public DataObjects AllObjects { get; } = new DataObjects();
public DataObjects FinalizeTable { get; set; } = new DataObjects();
public Queue<DataObject> FreachableQueue { get; set; } = new Queue<DataObject>();
public DataObjects GetGeneration(int gen) {
var g = new DataObjects();
foreach (var o in AllObjects) if (o.Generation == gen) g.Add(o);
return g;
}
public DataObjects Gen0 => GetGeneration(0);
public DataObjects Gen1 => GetGeneration(1);
public DataObjects Gen2 => GetGeneration(2);
}
void NewObject() {
var obj = new DataObject {
HasFinalizeMethod = Rand.Bool(0.3),
HasRoot = Rand.Bool(0.6),
Size = Rand.Int(1, 3),
Color = Rand.Color(),
Name = Guid.NewGuid().ToString(),
Generation = 0
};
int need = ObjHeaderSize + obj.Size; // 模擬大小
if (Gen0FreeSpace >= need) {
AllocateInGen0(obj);
} else {
GCCollect(obj); // 空間不足觸發收集
}
}
void AllocateInGen0(DataObject obj) {
manager.AllObjects.Add(obj);
if (obj.HasFinalizeMethod) manager.FinalizeTable.Add(obj);
RefreshPanels();
}
void GCCollect(DataObject newObj) {
// 1. 清理 Freachable
while (manager.FreachableQueue.Count > 0) {
manager.AllObjects.Remove(manager.FreachableQueue.Dequeue());
}
// 2. FinalizeTable → Freachable
foreach (var o in manager.FinalizeTable) if (!o.HasRoot) manager.FreachableQueue.Enqueue(o);
foreach (var o in manager.FreachableQueue) manager.FinalizeTable.Remove(o);
// 3. Gen0
var survivors = new DataObjects();
foreach (var o in manager.Gen0) {
if (!o.HasRoot && !o.HasFinalizeMethod) manager.AllObjects.Remove(o);
else { survivors.Add(o); o.Generation++; }
}
// 4. 嘗試放入 Gen1
if (Gen1FreeSpace >= survivors.TotalSize) {
foreach (var o in survivors) { /* 已晉升 */ }
} else {
HandleGen1(survivors); // 遞迴處理 Gen1
}
RefreshPanels();
}
每代對應一個 Panel,Paint 事件依物件 Size 繪製矩形,顯示 Name、HasRoot、Tag。
void panelGen0_Paint(object sender, PaintEventArgs e) {
var g = e.Graphics;
float x = 0;
foreach (var o in manager.Gen0) {
g.FillRectangle(new SolidBrush(o.Color), x, 0, o.Size * UnitWidth, 20);
g.DrawString($"[{o.Name}]{(o.HasRoot?"R":"")}", font, Brushes.Red, x, 0);
g.DrawString(o.Tag, font, Brushes.Red, x, 22);
x += o.Size * UnitWidth;
}
}
void RandomizeRoots() {
foreach (var o in manager.AllObjects)
if (o.HasRoot) o.HasRoot = Rand.Bool(0.9); // 10% 機率失去根
}
System.Timers.Timer 觸發 Panel.Refresh() 會跨執行緒存取 UI,需改用 System.Windows.Forms.Timer 或 Invoke原始碼下載:Jasen.GCShow.rar