現在的伺服器都是多個cpu,在.NET Framework 2.0在GC上有個新特性GCServer ,不知道有多少人用過這個東東。
關於GC可以看這篇文章GC是如何工作的,不同的代的大小是多少,文章中提到有三種模式的GC,分別對應最佳化不同類型的應用程式。
Server GC
這種類型的GC是針對伺服器端高輸送量和高擴充性進行最佳化的,那情況是一種長時間的載入和請求不停地分配和重新分配,並維持在較高水準的情況。
這種server GC 使用每個處理器一個堆、一個GC線程,並盡量的保持堆之間的平衡。在垃圾收集的時候,GC線程工作在各自的線程中,這樣就最小化了鎖資源,就保證了在這種應用條件下最有效工作。
這種類型的GC只有在多處理器的機器上可見,如果你在單一處理器上的設定這種模式,那你將得到實際啟動並執行模式是非並發的workstation版本(Non Concurrent)。現在的雙核也是這種模式,intel的超執行緒技術實現的cpu並不是真實的多cpu,因此它不會使用這種模式。
Asp.net 在多cpu的機器上預設使用這種模式,如果你想使用server GC模式,你可以在應用程式層級上做如下設定:
<configuration>
<runtime>
<gcServer enabled="true" />
</runtime>
</configuration>
Workstation GC – Concurrent
這種被用來作為winform應用程式和windows services 服務程式的預設設定。
這種模式是對互動的應用程式,這種程式要求應用程式不能暫停,即時一個相對很短暫的時間也是不行的。因為暫停進程會讓使用者介面閃爍或者當點擊按鈕的時候感覺應用程式沒有響應。
這種實現方式是當進行Gen 2 收集的時候,將cpu和記憶體的使用量作為更短的停頓時間。
Workstation GC – Non Concurrent
這種模式是模仿Server GC,只是收集是發生在引起GC的進程上,這種模式推薦為那種運行在單個cpu上的服務類型的應用程式。可以修改應用程式級上的配置來把 concurrency 關閉。
<configuration>
<runtime>
<gcConcurrent enabled="false" />
</runtime>
</configuration>
啟用GCServer有什麼意義呢,主要是會進行垃圾整理,這樣就可以避免垃圾脆片的問題影響。需要驗證這個問題的例子可以參見這篇文章Memory Management (III) - .NET CLR ?,文章中包含一個測試代碼。代碼如下:
class Program
{
static void Main(string[] args)
{
List<byte[]> buffer1 = new List<byte[]>();
List<byte[]> buffer2 = new List<byte[]>();
List<byte[]> buffer3 = new List<byte[]>();
// // allocate //
Console.WriteLine();
Console.WriteLine();
Console.WriteLine("1. Allocate 64mb block(s) as more as possible...");
try
{
while (true)
{
buffer1.Add(new byte[64 * 1024 * 1024]);
Console.Write("#");
buffer2.Add(new byte[64 * 1024 * 1024]);
Console.Write("#");
}
}
catch (OutOfMemoryException)
{
}
Console.WriteLine();
Console.WriteLine(" Total {0} blocks were allocated ( {1} MB).", (buffer1.Count + buffer2.Count), (buffer1.Count + buffer2.Count) * 64);
// // free //
Console.WriteLine();
Console.WriteLine();
Console.WriteLine("2. Free Blocks...");
buffer2.Clear();
Console.WriteLine(" Total: {0} blocks ({1} MB)", buffer1.Count, buffer1.Count * 64);
// // GC //
GC.Collect(GC.MaxGeneration);
// // allocate //
Console.WriteLine();
Console.WriteLine();
Console.WriteLine("3. Allocate 72mb block(s) as more as possible...");
try
{
while (true)
{
buffer3.Add(new byte[72 * 1024 * 1024]);
Console.Write("#");
}
}
catch (OutOfMemoryException)
{
}
Console.WriteLine();
Console.WriteLine(" Total: 64mb x {0}, 72mb x {1} blocks allocated( {2} MB).\n", buffer1.Count, buffer3.Count, buffer1.Count * 64 + buffer3.Count * 72);
Console.ReadLine();
}
}