廢話不多說了,本人是搞Web方向的,C/S不太熟悉,先看界面圖(比較粗糙),這裡僅僅是從一個視覺的 效果來初步顯示GC相對應的操作(簡單的效果顯示,並不是真正的GC內幕,那個我也不懂)

基本概念
對象的生成過程(newobj指令)
1:計算類型(包括基類)所有字段的字節總數
2: 字節總數再加上對象開銷字段字節數(相加為:對象所需的字節數)。每個對象包含2個開銷字段 :類型對象指針以及同步塊索引。WIN32中,各占32位,WIN64中,各占64位。
3:CLR檢測托管堆中是 否有足夠的空間滿足對象所需的字節數。如果滿足,對象將被分配在NextObjPtr指針指示的地方,實例構造器 被調用,(new操作)返回對象的內存地址。指針NextObjPtr越過對象所在的區域,指示下一個新建對象在托 管堆中的地址。如果不滿足,進行垃圾收集。
根
每一個應用程序都有一組根Root。一個根是一 個存儲地址,包含一個指向類型對象的指針。
該指針有2種形式:(1)指向托管堆中的一個對象。(2 )設為null。
根包括靜態字段,方法參數,局部變量,CPU寄存器。
對象的代
托管堆中 ,對象的代大概為0代,1代,2代,相應的內存容量為256K,2M,10M。當然,垃圾收集器也會自動調整預算容 量。
終結操作和釋放模式
終結操作(Finalize()方法)可以確保托管對象在釋放內存的同時 不會洩露本地資源,但是不能確定它在何時被調用。
釋放模式(Dispose()方法):當對象不再被使用 的時候顯示的釋放掉它所占有的資源。 (更多控制)注:可以用來控制在對象生命周期內資源的重復利用, 例如connection資源不一定每次操作都要關閉。
下序的代碼顯示了GC.Collect()方法將使Finalize( )方法被調用:
Code highlighting produced by Actipro CodeHighlighter (freeware)
http://www.CodeHighlighter.com/
--> public static class Program
{
static void Main(string[] args)
{
new GCNotice();
Timer timer = new Timer(TimerCallBack,null,0,2000);
Console.ReadLine();
timer.Dispose();
}
private static void TimerCallBack(object obj)
{
Console.WriteLine("GC START Time:"+DateTime.Now.ToString());
GC.Collect();
Console.WriteLine("GC END Time:" + DateTime.Now.ToString());
}
}
sealed class GCNotice
{
~GCNotice(){
Console.Beep();
Console.WriteLine("*********GCNotice FINALIZE():"+DateTime.Now.ToString());
if(!AppDomain.CurrentDomain.IsFinalizingForUnload())
{
new GCNotice();
}
}
}
~GCNotice(){
} 析構函數(C++)就是我們所說的終結操作(與C++不同),也 就是Finalize()方法。在下列事件中將觸發:
(1):第0代對象充滿時(垃圾收集)。
(2) :代碼顯示調用System.GC.Collect()。
(3):Windoms報告內存不足。
(4):CLR卸載應用 程序域。
(5):CLR關閉。
一般情況下,如果一個類型中本地資源需求比較大,建議使用 HandleCollector來促進GC.Collect()執行(釋放資源)。
代碼
Code highlighting produced by Actipro CodeHighlighter (freeware)
http://www.CodeHighlighter.com/
-->namespace System.Runtime.InteropServices
{
// 摘要:
// 跟蹤未處理的句柄,並在達到指定阈值時強制執行垃圾回收。
public sealed class HandleCollector
{
// 摘要:
// 使用一個名稱以及一個阈值(在達到該值時開始執行句柄回收)初始化
System.Runtime.InteropServices.HandleCollector
// 類的新實例。
//
// 參數:
// name:
// 回收器的名稱。此參數允許您為跟蹤句柄類型的回收器分別命名。
//
// initialThreshold:
// 指定何時開始執行回收的值。
//
[TargetedPatchingOptOut("Performance critical to inline this type of method across NGen
image boundaries")]
public HandleCollector(string name, int initialThreshold);
// 摘要:
// 增加當前句柄計數。
public void Add();
// 減少當前句柄計數。
//
public void Remove();
}
}
public HandleCollector(string name, int initialThreshold); //組合到類型 中,實例化
public void Add();//構造函數中運用
public void Remove();//析構函數中運用
終結鏈表與終結可達隊列
創建一個新對象時,如果對象的類型定義了Finalize()方法,那麼指 向該對象的指針將被放到終結鏈表中。終結鏈表上的每一個條目都引用著一個對象,指示GC在回收這些對象之 前調用它們的Finalize()方法。
主要過程如下
好了,概念的東西不再介紹了,本人思路如下:
(一)准備工作:創建一個DataObject類型(模擬一個對象實體),DataObjects(對象集合), DataObjectManager(對象集合管理)。
(二)初始化一個屬性值為隨機值的 DataObject對象
(三)判斷托管堆0代內存是否充足,如果滿足則分配對象內存(模擬)(如果有終結方法,則添加引用到終 結鏈表中)。如果不滿足,進行垃圾收集。
(四)垃圾收集操作:細分為0,1,2代的比較判斷與操作
(五)收集後內容的顯示,調用面板panel的refresh()方法。
(六)隨機修改原對象集合中的 對象的值 HasRoot為false(後來添加的),標識無根。
(一) 准備工作
先自創建一個類,主 要是以該對象來作為操作的。
Code highlighting produced by Actipro CodeHighlighter
(freeware)
http://www.CodeHighlighter.com/
--> public class DataObject : Jasen.GCShow.IDataObject
{
public Boolean HasFinalizeMethod { get; set; }
public Boolean HasRoot { get; set; }
public Int32 Number { get ;set; }
public System.Drawing.Color Color { get;set; }
public String OXString{
get{
//return (HasRoot ? "R" : "0") + (HasFinalizeMethod ? "F" : "");
return (HasFinalizeMethod ? "[F]" : "[!F]");
}
}
public String Name { get; set; }
public String NiceName { get; set; }
public Int32 Generation { get; set; }
}
然後就是該類對象集合,實現遍歷以及索引:
Code highlighting produced by
Actipro CodeHighlighter (freeware)
http://www.CodeHighlighter.com/
--> public class DataObjects : IEnumerable, Jasen.GCShow.IDataObjects
{
private List<DataObject> objectList=null;
public DataObjects(List<DataObject> objects) {
this.objectList = objects;
}
public DataObjects(){
this.objectList=new List<DataObject>();
}
public void Add(DataObject item)
{
if(!objectList.Contains(item)){
objectList.Add(item);
}
}
public void Remove(DataObject item)
{
if (objectList.Contains(item)){
objectList.Remove(item);
}
}
public int Count()
{
if(objectList==null){
return 0;
}
return objectList.Count;
}
public DataObject this[int i]{
get{
if (objectList != null && objectList.Contains(objectList[i])){
return objectList[i];
}
else{
return default(DataObject);
}
}
set{
objectList[i] = value;
}
}
#region IEnumerable 成員
IEnumerator IEnumerable.GetEnumerator()
{
for (int i = 0; i < objectList.Count(); i++)
{
yield return this[i];
}
}
#endregion
}
其次就是該對象集合的管理類,負責所有對象的ItemCollection,以及0,1,2代對象集合,以 及終結鏈表,終結可達隊列
Code highlighting produced by Actipro CodeHighlighter
(freeware)
http://www.CodeHighlighter.com/
--> 1 public class DataObjectManager : Jasen.GCShow.IDataObjectManager
{
DataObjects items = new DataObjects();
Queue<DataObject> freachableQueue = new Queue<DataObject>();
DataObjects finalizeTable = new DataObjects();
public DataObjects ItemsCollection
{
get { return items; }
set { items = value; }
}
public DataObjects ZeroGenerationCollection
{
get { return GetCollection(0); }
}
public DataObjects GetCollection(int generation)
{
if (ItemsCollection.Count() == 0) return null;
DataObjects generationObjects = new DataObjects();
foreach(DataObject obj in ItemsCollection){
if(obj.Generation==generation){
generationObjects.Add(obj);
}
}
return generationObjects;
}
public DataObjects OneGenerationCollection
{
get { return GetCollection(1); }
}
public DataObjects TwoGenerationCollection
{
get { return GetCollection(2); }
}
public DataObjects FinalizeTable
{
get { return finalizeTable; }
set { finalizeTable = value; }
}
public Queue<DataObject> FreachableQueue
{
get { return freachableQueue; }
set { freachableQueue = value; }
}
}
(二)初始化一個屬性值為隨機值的 DataObject對象
通過隨機設置類的值來實例化一 個對象
Code highlighting produced by Actipro CodeHighlighter (freeware)
http://www.CodeHighlighter.com/
-->DataObject item = new DataObject()
{
HasFinalizeMethod = Randoms.GetRandomBoolen(0.3),
HasRoot = Randoms.GetRandomBoolen(0.6),
Color = Randoms.GetRandomColor(),
Number = Randoms.RandomNum(1, 3),
Name = Guid.NewGuid().ToString(),
NiceName = Randoms.AddNum().ToString(),
Generation = 0 // 默認為0代
};
以上的值大部分是隨機的,不確定的,比如下面的方法----->返回隨機比例為 rate(比如0.3)的true值,它等價於有30%的概率返回true,70%概率返回false,
Code
highlighting produced by Actipro CodeHighlighter (freeware)
http://www.CodeHighlighter.com/
--> /// <summary>
/// 返回隨機比例為rate的 true值
/// </summary>
/// <param name="rate"></param>
/// <returns></returns>
public static Boolean GetRandomBoolen(double rate) {
if (rate < 0 || rate > 1) throw new ArgumentOutOfRangeException("rate must be
between 0 to 1");
Random random = new Random((int)DateTime.Now.Ticks);
System.Threading.Thread.Sleep(100);
if(random.Next(0,10000)>=10000*(1-rate)){
return true;
}
return false;
}
隨機顏色如下
Code highlighting produced by Actipro CodeHighlighter
(freeware)
http://www.CodeHighlighter.com/
--> public static Color GetRandomColor()
{
Random randomFirst = new Random((int)DateTime.Now.Ticks);
System.Threading.Thread.Sleep(300);
Random randomSencond = new Random((int)DateTime.Now.Ticks);
System.Threading.Thread.Sleep(300);
Random randomThird = new Random((int)DateTime.Now.Ticks);
int intRed = randomFirst.Next(256);
int intGreen = randomSencond.Next(256);
int intBlue = randomThird.Next(256);
return Color.FromArgb(intRed, intGreen, intBlue);
}
(三)判斷托管堆0代內存是否充足
判斷的大概過程如下:
Code
highlighting produced by Actipro CodeHighlighter (freeware)
http://www.CodeHighlighter.com/
--> #region newobject指令過程
private Int32 CHARTOTALNUMBER = 0;
private void NewObjectOperationProcess(DataObject item){
//計算類型所有字段的字節總數
CHARTOTALNUMBER = CountTypeCharTotalNumber(item);
//計算2個開銷字段:類型對象指針,同步塊索引 WIN32--32位×2=64位=8字節
CountObjectExtraCharNumber();
//判斷0代對象內存(256K)是否含有所需的字節數 (長度)
Boolean isEnough= CheckZeroGenerationHasEnoughChars();
//計算新建對象在托管堆中的地址 (長度)
if (isEnough)
{
RefreshZeroGenenrationAndFinalizeTable(item);
}
else {
//回收垃圾
GCCollect(item);
}
}
如果托管堆0代內存充足,那麼顯示如下:

上面顯示的是對象含有根,沒有終結方法。我們來看一張含有終結方法的圖,含有終結方法的對 象會被添加引用到終結鏈表中,如下:

(四)垃圾收集操作:細分為0,1,2代的比較判斷與操作
(1)處理托管堆0代對象的主 要操作如下:
Code highlighting produced by Actipro CodeHighlighter (freeware)
http://www.CodeHighlighter.com/
--> private void GCSystemOperation()
{
ClearFreachableQueue();
DataObjects temps = new DataObjects();
//清理沒根的沒終結方法的0代對象 0代對象 +1 (清除)
DataObjects list = manager.ZeroGenerationCollection;
if (list == null) return;
foreach (DataObject obj in list)
{
//如果對象沒有根 並且沒有終結方法
if (obj.HasRoot == false && obj.HasFinalizeMethod == false){
manager.ItemsCollection.Remove(obj);
}
else
{
temps.Add(obj);
//obj.Generation++;
}
}
if(temps.Count()>0){
int tempsLength=CountSize(temps);
int oneGenerationCurrentLength = CountSize(manager.OneGenerationCollection);
Boolean isOneGenerationEnough = (SystemConst.OneGenerationLength-
oneGenerationCurrentLength > tempsLength)?true:false;
if (isOneGenerationEnough)
{
GenerationAddOne(temps);
}
else {
//處理托管堆1代對象
MessageBox.Show("處理托管堆1代對象!");
HandleOneGeneration(temps);
}
}
}
當一直添加對象時,達到如下情況:

我們不知道下一個對象的內存大小,很有下一次就會可能發生垃圾收集。如下圖所示,當托管堆0 代對象內存容量不足時,會觸發垃圾收集:

其中先清理可達隊列中的數據對象,(含有Finalize()終結方法並且無根,一般情況為在第1次收 集時將終結鏈表中的指針移動至終結可達隊列中,這樣可達隊列中才有指針。第2次收集就會將可達隊列中的 指針清理)

執行下列代碼:
Code highlighting produced by Actipro CodeHighlighter
(freeware)
http://www.CodeHighlighter.com/
--> 1 private void ClearFreachableQueue()
{
//清理終結可達隊列中的對象 沒根 有終結方法 (清除) 一般為清理上次收集數據
while (manager.FreachableQueue.Count > 0){
DataObject obj = manager.FreachableQueue.Dequeue();
manager.ItemsCollection.Remove(obj);
}
MessageBox.Show("清理可達隊列對象");
//終結鏈表中的數據 --》可達隊列
foreach (DataObject item in manager.FinalizeTable){
if (item.HasRoot == false){
manager.FreachableQueue.Enqueue(item);
}
}
MessageBox.Show("將終結鏈表中的可達對象移動至可達隊列");
foreach (DataObject obj in manager.FreachableQueue){
manager.FinalizeTable.Remove(obj);
}
MessageBox.Show("移除終結鏈表中包含的可達隊列對象");
}
顯然,將終結鏈表的數據移動到可達隊列後,然後再移除終結鏈表包含的可達隊列的指針 ,操作後如下:

(2)處理托管堆1代對象的主要操作如下:
Code highlighting produced by Actipro
CodeHighlighter (freeware)
http://www.CodeHighlighter.com/
--> private void HandleOneGeneration(DataObjects temps)
{
DataObjects currentTempObjects = new DataObjects();
foreach(DataObject obj in manager.OneGenerationCollection){
if (obj.HasRoot == false && obj.HasFinalizeMethod == false){
manager.ItemsCollection.Remove(obj);
}
else {
currentTempObjects.Add(obj);
}
}
if (currentTempObjects.Count() > 0)
{
Boolean enough = CheckTwoGenerationEnough(currentTempObjects);
if (enough)
{
MessageBox.Show("托管堆2代內存充足----》托管堆1代對象 對象代+1");
GenerationAddOne(currentTempObjects);
}
else {
MessageBox.Show("托管堆2代內存不足----》處理");
HandleTwoGeneration(currentTempObjects);
}
}
MessageBox.Show("托管堆0代對象 對象代+1");
GenerationAddOne(temps);
}
繼續創建新的對象:

發現越來越多的對象在托管堆1代中存在。

一直增加,當托管堆0代對象內存不足,並且托管堆1代對象內存也不足時候,將導致1代對象的代 +1;其中也包括1代對象的清理工作,移除無根的對象。

(3)處理托管堆2代對象的主要操作如下:
Code highlighting produced by Actipro
CodeHighlighter (freeware)
http://www.CodeHighlighter.com/
--> 1 private void HandleTwoGeneration(DataObjects currentTempObjects)
{
Boolean enough = CheckTwoGenerationEnough(currentTempObjects);
if (enough){
GenerationAddOne(currentTempObjects);
}
else {
MessageBox.Show("托管堆2代對象內存滿了,清理托管堆2代無根對象");
ClearGenerationUnusefulObject(manager.TwoGenerationCollection);
if (CheckGenerationEnough(currentTempObjects, manager.TwoGenerationCollection,
SystemConst.TwoGenerationLength)){
MessageBox.Show("托管堆1代對象 對象代+1");
GenerationAddOne(currentTempObjects);
}
else{
ClearToEmpty(); //托管堆對象全部清理
}
}
}
(五)垃圾收集後內容的顯示,調用面板panel的refresh()方法。
例如托管堆0代 的面板刷新
Code highlighting produced by Actipro CodeHighlighter (freeware)
http://www.CodeHighlighter.com/
--> private void panelZeroGenenration_Paint(object sender, PaintEventArgs e)
{
if (manager.ItemsCollection.Count() == 0) { return; }
DataObjects list = manager.ZeroGenerationCollection;
if(list==null)return;
Graphics graphics = e.Graphics;
FillRectangle(graphics, list, true,true );
}
相應的面板繪制如下,采用累加來計算繪制的坐標(left)
Code highlighting
produced by Actipro CodeHighlighter (freeware)
http://www.CodeHighlighter.com/
--> 1 private void FillRectangle(Graphics graphic, DataObjects list,Boolean
markArrows,Boolean markOX)
{
float left = 0,width = 0,top = 0,height = 20,rams=-15;
for (int i = 0; i < list.Count(); i++){
int sum = 0;
if (i != 0) {
for (int z = 0; z < i; z++){
sum += list[z].Number;//i-1次
}
}
left = sum * SystemConst.GraphicLength;
width = SystemConst.GraphicLength * list[i].Number;
graphic.FillRectangle(new SolidBrush(list[i].Color), left, top, width, height);
graphic.FillRectangle(new SolidBrush(Color.Red), left, top, 2, height);
graphic.DrawString(("[" + list[i].NiceName + "]" + (list[i].HasRoot ? "R" : "")), smallFont, new SolidBrush(Color.Red), left, top);
if(markOX){
graphic.DrawString(list[i].OXString, smallFont, new SolidBrush(Color.Red), left, top + 40);
}
}
if(markArrows){
graphic.DrawString("↑", bigFont, new SolidBrush(Color.Red), left + width+rams, top + 20);
}
}
(六)隨機修改原對象集合中的對象的值 HasRoot為false(後來添加的),標識無根。
Code highlighting produced by Actipro CodeHighlighter (freeware)
http://www.CodeHighlighter.com/
--> 1 /// <summary>
/// 隨機修改對象的根為 false
/// </summary>
private void RandomChangeItemsRootValue()
{
DataObjects list = manager.ItemsCollection;
if (list == null) return;
foreach (DataObject item in list){
if (item.HasRoot == true){
item.HasRoot = Randoms.GetRandomBoolen(0.9);
}
}
}
最後顯示如下(托管堆0代對象+1,1代對象+1):

同時我們應該注意到:在第6步中的方法隨機的修改了集合中對象的HasRoot屬性,再看下下一張 圖:

將上面圖對照,發現用紫色框標識的 [36]R [39]R轉變成了[36] [39],從這裡發現從 有根 ---->無根 轉變了。這和GC中無根對象才會被回收是一個道理。
當托管堆對象2代滿了時會自動清 理0,1,2代的垃圾。有一個特殊情況,當1代中對象代+1後,轉變為2代,與原來2代的對象總共的內存超過了 容量,就有可能使應用程序中斷。(不過本人這裡也不太清楚,本人將所有的對象之空,設置為null)
最後一點:本來想用Timer來定時觸發對象的生成操作,代碼如下:
Code highlighting
produced by Actipro CodeHighlighter (freeware)
http://www.CodeHighlighter.com/
--> 1 private void btnAutoAdd_Click(object sender, EventArgs e)
{
timer = new System.Timers.Timer(3000);
timer.Elapsed += new System.Timers.ElapsedEventHandler(timer_Tick);
timer.AutoReset = true;
timer.Enabled = true;
btnAutoAdd.Enabled = false;
btnAutoStop.Enabled = true;
}
public void timer_Tick(object sender, ElapsedEventArgs e) {
NewOneObjectOperation();
}
private void btnAutoStop_Click(object sender, EventArgs e)
{
timer.Stop();
btnAutoAdd.Enabled = true;
btnAutoStop.Enabled = false;
}
但是對於Panel的refresh()操作也是線程的,這樣的話將觸發異常:

本示例的目的是用一種視覺的效果來看我們.NET平台下的垃圾收集過程,本人水平有限,難免有N 多BUG以及不太清楚的地方,還請各位多多指教。
本GC初步模擬程序代碼下載地址:Jasen.GCShow.rar [GC初步模擬效果程序 ]
http://files.cnblogs.com/jasenkin/Jasen.GCShow.rar