Chúng tôi đang chạy một trang trại sử dụng .NET. Mỗi máy chủ web chứa một lượng đáng kể các đối tượng tĩnh trong bộ nhớ của nó. Một bộ sưu tập rác Gen 2 (GC) mất 10-20 giây và nó chạy mỗi 5 phút. Chúng tôi đã chạy nhiều hoặc ít hơn vào cùng một vấn đề mà StackOverflow gặp phải: http://samsaffron.com/archive/2011/10/28/in-managed-code-we-trust-our-recent-battles-with-the-net-garbage-collectorThông báo Thu gom Rác Bỏ lỡ
Hiện tại, chúng tôi đang giảm số đối tượng trong bộ nhớ cache. Tuy nhiên, điều này cần có thời gian.
Đồng thời, chúng tôi đã triển khai các phương pháp được ghi thành tài liệu here để nhận thông báo trong .NET về việc tiếp cận các GC. Mục tiêu là đưa máy chủ web ra khỏi trang trại khi GC đang tiếp cận và đưa nó vào trang trại sau khi GC kết thúc. Tuy nhiên, chúng tôi chỉ nhận được thông báo cho 0,7% tổng số GC. Chúng tôi đang sử dụng một maxGenerationThreshold và largeObjectHeapThreshold của 8. Chúng tôi đã thử các ngưỡng khác, nhưng số lượng GC bị mất không thay đổi.
Chúng tôi đang sử dụng bộ sưu tập rác máy chủ đồng thời (http://msdn.microsoft.com/en-us/library/ms229357.aspx). Mã GCLatencyMode tương tác (xem http://msdn.microsoft.com/en-us/library/system.runtime.gclatencymode.aspx). Ở đây một lần nữa, chúng tôi đã cố gắng sử dụng các chế độ GC khác (Chế độ máy trạm, Hàng loạt, v.v.). Và một lần nữa, chúng tôi không nhận được thông báo cho hầu hết các GC.
Chúng tôi có đang làm gì sai hay không thể nhận được thông báo cho mọi GC xảy ra? Làm cách nào để tăng số lượng thông báo?
Theo http://assets.red-gate.com/community/books/assets/Under_the_Hood_of_.NET_Management.pdf, khi bắt đầu GC được kích hoạt khi Gen2 chạm ~ 10 MB. Chúng tôi có rất nhiều RAM, vì vậy nếu chúng tôi có thể đặt ngưỡng này theo cách thủ công ở cấp cao hơn, sẽ mất nhiều thời gian hơn để đạt đến ngưỡng này và theo hiểu biết của tôi, xác suất sẽ tăng lên để nhận thông báo. Có cách nào để sửa đổi ngưỡng này không?
Đây là mã dùng để đăng ký và nghe thông báo:
GC.RegisterForFullGCNotification(gcThreshold, gcThreshold);
// Start a thread using WaitForFullGCProc.
thWaitForFullGC = new Thread(WaitForFullGCProc);
thWaitForFullGC.Name = "HealthTestGCNotificationListenerThread (Threshold=" + gcThreshold + ")";
thWaitForFullGC.IsBackground = true;
WaitForFullGCProc():
private void WaitForFullGCProc()
{
try
{
while (!gcAbort)
{
// Check for a notification of an approaching collection.
GCNotificationStatus s;
do
{
int timeOut = CheckForMissedGc() > 0 ? 5000 : (10 * 60 * 1000);
s = GC.WaitForFullGCApproach(timeOut);
if (this.GcState == GCState.InducedUnnotified)
{
// Set the GcState back to okay to prevent the message from staying in the ApplicationMonitoring.
this.GcState = GCState.Okay;
}
} while (s == GCNotificationStatus.Timeout);
if (s == GCNotificationStatus.Succeeded)
{
SetGcState(GCState.Approaching, "GC is approaching..");
gcApproachNotificationCount++;
}
else
{
...
}
Stopwatch stopwatch = Stopwatch.StartNew();
s = GC.WaitForFullGCComplete((int)PrewarnTime.TotalMilliseconds);
long elapsed = stopwatch.ElapsedMilliseconds;
if (s == GCNotificationStatus.Timeout)
{
if (this.ForceGCWhenApproaching && !this.IsInGc && !this.IsPeriodicGcApproaching)
{
this.IsInGc = true;
GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced, blocking: true);
GC.WaitForPendingFinalizers();
elapsed = stopwatch.ElapsedMilliseconds;
this.IsInGc = false;
}
}
}
gcAbort = false;
}
catch (Exception e)
{
}
}
bạn có thể có thể gửi mã nơi bạn đăng ký và nghe thông báo GC? – Alex
'GC.RegisterForFullGCNotification (gcThreshold, gcThreshold); // Bắt đầu chuỗi bằng WaitForFullGCProc. thWaitForFullGC = chủ đề mới (WaitForFullGCProc); thWaitForFullGC.Name = "HealthTestGCNotificationListenerThread (Ngưỡng =" + gcThreshold + ")"; thWaitForFullGC.IsBackground = true; – kopernik