我正在尝试使用这个c#代码来更好地理解.Net环境中的垃圾收集。此代码将无限数组分配到列表中,后台线程处理垃圾回收通知。垃圾收集工作当然可以通过不时检查load.Count进行测试,并看到数字正在减少。我的问题实际上是为什么这些对象被垃圾收集?因为它们被列在一个列表中,所以它们仍被引用,并且根据我的理解,它们不应被收集。
代码示例取自MSDN。
class Program
{
// Variable for continual checking in the
// While loop in the WaitForFullGCProc method.
static bool checkForNotify = false;
// Variable for suspending work
// (such servicing allocated server requests)
// after a notification is received and then
// resuming allocation after inducing a garbage collection.
static bool bAllocate = false;
// Variable for ending the example.
static bool finalExit = false;
// Collection for objects that
// simulate the server request workload.
static List<byte[]> load = new List<byte[]>();
public static void Main(string[] args)
{
try
{
// Register for a notification.
GC.RegisterForFullGCNotification(10, 10);
Console.WriteLine("Registered for GC notification.");
checkForNotify = true;
bAllocate = true;
// Start a thread using WaitForFullGCProc.
Thread thWaitForFullGC = new Thread(new ThreadStart(WaitForFullGCProc));
thWaitForFullGC.Start();
// While the thread is checking for notifications in
// WaitForFullGCProc, create objects to simulate a server workload.
try
{
int lastCollCount = 0;
int newCollCount = 0;
while (true)
{
if (bAllocate)
{
load.Add(new byte[1000]);
newCollCount = GC.CollectionCount(2);
if (newCollCount != lastCollCount)
{
// Show collection count when it increases:
Console.WriteLine("Gen 2 collection count: {0}", GC.CollectionCount(2).ToString());
lastCollCount = newCollCount;
}
// For ending the example (arbitrary).
if (newCollCount == 500)
{
finalExit = true;
checkForNotify = false;
break;
}
}
}
}
catch (OutOfMemoryException)
{
Console.WriteLine("Out of memory.");
}
finalExit = true;
checkForNotify = false;
GC.CancelFullGCNotification();
}
catch (InvalidOperationException invalidOp)
{
Console.WriteLine("GC Notifications are not supported while concurrent GC is enabled.\n"
+ invalidOp.Message);
}
}
public static void OnFullGCApproachNotify()
{
Console.WriteLine("Redirecting requests.");
// Method that tells the request queuing
// server to not direct requests to this server.
RedirectRequests();
// Method that provides time to
// finish processing pending requests.
FinishExistingRequests();
// This is a good time to induce a GC collection
// because the runtime will induce a full GC soon.
// To be very careful, you can check precede with a
// check of the GC.GCCollectionCount to make sure
// a full GC did not already occur since last notified.
GC.Collect();
Console.WriteLine("Induced a collection.");
}
public static void OnFullGCCompleteEndNotify()
{
// Method that informs the request queuing server
// that this server is ready to accept requests again.
AcceptRequests();
Console.WriteLine("Accepting requests again.");
}
public static void WaitForFullGCProc()
{
while (true)
{
// CheckForNotify is set to true and false in Main.
while (checkForNotify)
{
// Check for a notification of an approaching collection.
GCNotificationStatus s = GC.WaitForFullGCApproach();
if (s == GCNotificationStatus.Succeeded)
{
Console.WriteLine("GC Notification raised.");
OnFullGCApproachNotify();
}
else if (s == GCNotificationStatus.Canceled)
{
Console.WriteLine("GC Notification cancelled.");
break;
}
else
{
// This can occur if a timeout period
// is specified for WaitForFullGCApproach(Timeout)
// or WaitForFullGCComplete(Timeout)
// and the time out period has elapsed.
Console.WriteLine("GC Notification not applicable.");
break;
}
// Check for a notification of a completed collection.
s = GC.WaitForFullGCComplete();
if (s == GCNotificationStatus.Succeeded)
{
Console.WriteLine("GC Notifiction raised.");
OnFullGCCompleteEndNotify();
}
else if (s == GCNotificationStatus.Canceled)
{
Console.WriteLine("GC Notification cancelled.");
break;
}
else
{
// Could be a time out.
Console.WriteLine("GC Notification not applicable.");
break;
}
}
Thread.Sleep(500);
// FinalExit is set to true right before
// the main thread cancelled notification.
if (finalExit)
{
break;
}
}
}
private static void RedirectRequests()
{
// Code that sends requests
// to other servers.
// Suspend work.
bAllocate = false;
}
private static void FinishExistingRequests()
{
// Code that waits a period of time
// for pending requests to finish.
// Clear the simulated workload.
load.Clear();
}
private static void AcceptRequests()
{
// Code that resumes processing
// requests on this server.
// Resume work.
bAllocate = true;
}
}
答案 0 :(得分:3)
以下是我修改过的程序版本:
class Program
{
List<byte[]> myJunkList = new List<byte[]>();
static void Main(string[] args)
{
var program = new Program();
program.Run();
}
public void Run()
{
GC.RegisterForFullGCNotification(10, 10);
var pollingThread = new Thread(() =>
{
while (true)
{
var gcStatus = GC.WaitForFullGCApproach(1000);
switch (gcStatus)
{
case GCNotificationStatus.Succeeded:
Console.WriteLine("GC has started.");
break;
}
gcStatus = GC.WaitForFullGCComplete(1000);
switch (gcStatus)
{
case GCNotificationStatus.Succeeded:
Console.WriteLine("GC has ended.");
break;
}
Thread.Sleep(500);
}
});
pollingThread.Start();
AllocateMemory();
GC.CancelFullGCNotification();
}
void AllocateMemory()
{
var rand = new Random();
var newCount = 0;
var oldCount = 0;
while (true)
{
var junk = new byte[1024];
rand.NextBytes(junk);
myJunkList.Add(junk);
newCount = GC.CollectionCount(2);
if (newCount != oldCount)
{
Console.WriteLine("GC 2 has run {0} times (list now has {1} items).", newCount, myJunkList.Count);
}
oldCount = newCount;
}
}
输出显示:
GC has started.
GC 2 has run 1 times (list now has 14935 items).
GC has ended.
GC 2 has run 2 times (list now has 33146 items).
GC 2 has run 3 times (list now has 55403 items).
GC 2 has run 4 times (list now has 95877 items).
GC 2 has run 5 times (list now has 166723 items).
GC has ended.
GC 2 has run 6 times (list now has 292218 items).
GC has ended.
GC has ended.
GC 2 has run 7 times (list now has 539165 items).
GC has ended.
GC has ended.
GC has ended.
GC 2 has run 8 times (list now has 986512 items).
GC has ended.
GC has ended.
GC has started.
GC has ended.
GC has started.
如您所见,列表不正在收集,最终您会按预期获得OutOfMemoryException
。