Notifiche di Garbage Collection
In alcune situazioni un'operazione completa di Garbage Collection eseguita da Common Language Runtime può influire negativamente sulle prestazioni. Questo può rappresentare un problema in modo particolare con server che elaborano grandi volumi di richieste. In questo caso, un processo di Garbage Collection lungo può provocare un timeout delle richieste. Per impedire che si verifichi un'operazione completa di Garbage Collection durante un periodo critico, è possibile ricevere una notifica quando questa operazione sta per essere eseguita e intraprendere quindi un'azione per reindirizzare il carico di lavoro a un'altra istanza del server. È anche possibile forzare una raccolta, purché l'istanza del server corrente non richieda l'elaborazione di richieste.
Nota |
---|
Questa funzionalità è disponibile solo se l'operazione di Garbage Collection in modalità simultanea è disabilitata.Per impostazione predefinita, tale operazione è attivata a meno che non si utilizzi un ambiente di hosting e l'host abbia modificato la configurazione.L'operazione di Garbage Collection in modalità simultanea non è disponibile quando si utilizza la Garbage Collection su server.Questa funzionalità non supporta l'operazione di Garbage Collection in modalità simultanea perché mentre tale operazione è in corso sono consentite allocazioni di memoria.Per informazioni su come disabilitare l'operazione di Garbage Collection in modalità simultanea, vedere l'impostazione di runtime <gcConcurrent>. |
Il metodo RegisterForFullGCNotification esegue la registrazione per la generazione di una notifica quando il runtime riconosce che sta per verificarsi un'operazione completa di Garbage Collection. Questa notifica è composta da due parti: quando sta per verificarsi l'operazione completa di Garbage Collection e quando tale operazione è stata completata.
Per determinare quando è stata generata una notifica, utilizzare i metodi WaitForFullGCApproach e WaitForFullGCComplete. In genere, questi metodi vengono utilizzati in un ciclo while per ottenere continuamente un'enumerazione GCNotificationStatus che mostra lo stato della notifica. Se il valore è Succeeded, è possibile effettuare le operazioni seguenti:
In risposta a una notifica ottenuta con il metodo WaitForFullGCApproach, è possibile reindirizzare il carico di lavoro e possibilmente forzare una raccolta.
In risposta a una notifica ottenuta con il metodo WaitForFullGCComplete, è possibile rendere disponibile l'istanza del server corrente per elaborare nuovamente le richieste. È anche possibile raccogliere informazioni. Ad esempio, è possibile utilizzare il metodo CollectionCount per registrare il numero di raccolte.
I metodi WaitForFullGCApproach e WaitForFullGCComplete sono progettati per essere utilizzati insieme. L'utilizzo di uno senza l'altro può produrre risultati imprevisti.
Operazione completa di Garbage Collection
Il runtime provoca un'operazione completa di Garbage Collection se si verifica uno degli scenari seguenti:
Una quantità sufficiente di memoria passa nella generazione 2 per generare la successiva raccolta di generazione 2.
Una quantità sufficiente di memoria passa nell'heap degli oggetti grandi per generare la successiva raccolta di generazione 2.
Viene eseguita l'escalation di una raccolta di generazione 1 in una raccolta di generazione 2 a causa di altri fattori.
Le soglie specificate nel metodo RegisterForFullGCNotification si applicano ai primi due scenari. Tuttavia, nel primo scenario non si riceverà sempre la notifica nel momento proporzionale ai valori di soglia specificati, per due motivi:
Il runtime non controlla ogni allocazione di oggetti piccoli (per motivi di prestazioni).
Solo le raccolte di generazione 1 passano la memoria nella generazione 2.
Anche il terzo scenario contribuisce ad aumentare l'incertezza sul momento in cui si riceverà la notifica. Anche se non è garantita, questa soluzione si dimostra utile per attenuare gli effetti di un'operazione completa di Garbage Collection inopportuna, reindirizzando le richieste durante questo periodo o forzando la raccolta in un momento più favorevole.
Parametri di soglia delle notifiche
Il metodo RegisterForFullGCNotification include due parametri per specificare i valori di soglia degli oggetti di generazione 2 e dell'heap degli oggetti grandi. Quando vengono raggiunti tali valori, dovrebbe essere generata una notifica di Garbage Collection. Nella tabella seguente vengono descritti tali parametri.
Parametro |
Descrizione |
---|---|
maxGenerationThreshold |
Numero compreso tra 1 e 99 che specifica quando generare la notifica in base agli oggetti passati alla generazione 2. |
largeObjectHeapThreshold |
Numero compreso tra 1 e 99 che specifica quando generare la notifica in base agli oggetti allocati nell'heap degli oggetti grandi. |
Se si specifica un valore troppo alto, esiste un'elevata probabilità che si riceverà una notifica, ma il periodo di attesa potrebbe essere eccessivamente lungo prima che il runtime provochi una raccolta. Se si forza una raccolta, è possibile che venga recuperato un numero di oggetti maggiore rispetto a quelli che verrebbero recuperati se la raccolta viene provocata dal runtime.
Se si specifica un valore eccessivamente basso, il runtime può provocare la raccolta prima che sia trascorso un periodo di tempo sufficiente per ricevere una notifica.
Esempio
Descrizione
Nell'esempio seguente un gruppo di server gestisce le richieste Web in ingresso. Per simulare il carico di lavoro dell'elaborazione delle richieste, vengono aggiunte matrici di byte a un insieme List<T>. Ogni server esegue la registrazione per una notifica di Garbage Collection, quindi avvia un thread sul metodo utente WaitForFullGCProc per controllare continuamente l'enumerazione GCNotificationStatus restituita dai metodi WaitForFullGCApproach e WaitForFullGCComplete.
I metodi WaitForFullGCApproach e WaitForFullGCComplete chiamano i rispettivi metodi utente di gestione eventi quando viene generata una notifica:
OnFullGCApproachNotify
Questo metodo chiama il metodo utente RedirectRequests che indica al server di accodamento delle richieste di sospendere l'invio di richieste al server. Questa situazione viene simulata impostando la variabile a livello di classe bAllocate su false in modo che non vengano più allocati oggetti.
Quindi, viene chiamato il metodo utente FinishExistingRequests per completare l'elaborazione delle richieste in sospeso al server. Questa situazione viene simulata cancellando l'insieme List<T>.
Infine, viene forzata un'operazione di Garbage Collection perché il carico di lavoro è ridotto.
OnFullGCCompleteNotify
Questo metodo chiama il metodo utente AcceptRequests per riprendere ad accettare richieste, perché il server non è più soggetto a un'operazione completa di Garbage Collection. Questa azione viene simulata impostando la variabile bAllocate su true in modo che gli oggetti possano riprendere a essere aggiunti List<T>.
Il codice seguente contiene il metodo Main dell'esempio.
' Variables for continual checking in the
' While loop in the WaitForFullGcProc method.
Private Shared checkForNotify As Boolean = False
' Variable for suspending work
' (such as servicing allocated server requests)
' after a notification is received and then
' resuming allocation after inducing a garbage collection.
Private Shared bAllocate As Boolean = False
' Variable for ending the example.
Private Shared finalExit As Boolean = False
' Collection for objects that
' simulate the server request workload.
Private Shared load As New List(Of Byte())
Public Shared Sub Main(ByVal args() As String)
Try
' Register for a notification.
GC.RegisterForFullGCNotification(10, 10)
Console.WriteLine("Registered for GC notification.")
bAllocate = True
checkForNotify = True
' Start a thread using WaitForFullGCProc.
Dim thWaitForFullGC As Thread = _
New Thread(New ThreadStart(AddressOf WaitForFullGCProc))
thWaitForFullGC.Start()
' While the thread is checking for notifications in
' WaitForFullGCProc, create objects to simulate a server workload.
Try
Dim lastCollCount As Integer = 0
Dim newCollCount As Integer = 0
While (True)
If bAllocate = True Then
load.Add(New Byte(1000) {})
newCollCount = GC.CollectionCount(2)
If (newCollCount <> lastCollCount) Then
' Show collection count when it increases:
Console.WriteLine("Gen 2 collection count: {0}", _
GC.CollectionCount(2).ToString)
lastCollCount = newCollCount
End If
' For ending the example (arbitrary).
If newCollCount = 500 Then
finalExit = True
checkForNotify = False
bAllocate = False
Exit While
End If
End If
End While
Catch outofMem As OutOfMemoryException
Console.WriteLine("Out of memory.")
End Try
finalExit = True
checkForNotify = False
GC.CancelFullGCNotification()
Catch invalidOp As InvalidOperationException
Console.WriteLine("GC Notifications are not supported while concurrent GC is enabled." _
& vbLf & invalidOp.Message)
End Try
End Sub
// 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);
}
}
private:
// 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<array<Byte>^>^ load = gcnew List<array<Byte>^>();
public:
static void Main()
{
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 = gcnew Thread(gcnew 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(gcnew array<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);
}
}
Il codice seguente contiene il metodo utente WaitForFullGCProc, che contiene un ciclo while continuo per le notifiche di Garbage Collection.
Public Shared Sub WaitForFullGCProc()
While True
' CheckForNotify is set to true and false in Main.
While checkForNotify
' Check for a notification of an approaching collection.
Dim s As GCNotificationStatus = GC.WaitForFullGCApproach
If (s = GCNotificationStatus.Succeeded) Then
Console.WriteLine("GC Notifiction raised.")
OnFullGCApproachNotify()
ElseIf (s = GCNotificationStatus.Canceled) Then
Console.WriteLine("GC Notification cancelled.")
Exit While
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.")
Exit While
End If
' Check for a notification of a completed collection.
s = GC.WaitForFullGCComplete
If (s = GCNotificationStatus.Succeeded) Then
Console.WriteLine("GC Notifiction raised.")
OnFullGCCompleteEndNotify()
ElseIf (s = GCNotificationStatus.Canceled) Then
Console.WriteLine("GC Notification cancelled.")
Exit While
Else
' Could be a time out.
Console.WriteLine("GC Notification not applicable.")
Exit While
End If
End While
Thread.Sleep(500)
' FinalExit is set to true right before
' the main thread cancelled notification.
If finalExit Then
Exit While
End If
End While
End Sub
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 Notifiction 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;
}
}
}
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 Notifiction 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;
}
}
}
Il codice seguente contiene il metodo OnFullGCApproachNotify chiamato dal
metodo WaitForFullGCProc.
Public Shared Sub 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 ful 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.")
End Sub
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 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.");
}
Il codice seguente contiene il metodo OnFullGCApproachComplete chiamato dal
metodo WaitForFullGCProc.
Public Shared Sub OnFullGCCompleteEndNotify()
' Method that informs the request queuing server
' that this server is ready to accept requests again.
AcceptRequests()
Console.WriteLine("Accepting requests again.")
End Sub
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 OnFullGCCompleteEndNotify()
{
// Method that informs the request queuing server
// that this server is ready to accept requests again.
AcceptRequests();
Console::WriteLine("Accepting requests again.");
}
Il codice seguente contiene i metodi utente chiamati dai metodi OnFullGCApproachNotify e OnFullGCCompleteNotify. I metodi utente reindirizzano le richieste, completano le richieste esistenti, quindi riprendono le richieste dopo che si è verificata un'operazione completa di Garbage Collection.
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;
}
private:
static void RedirectRequests()
{
// Code that sends requests
// to other servers.
// Suspend work.
bAllocate = false;
}
static void FinishExistingRequests()
{
// Code that waits a period of time
// for pending requests to finish.
// Clear the simulated workload.
load->Clear();
}
static void AcceptRequests()
{
// Code that resumes processing
// requests on this server.
// Resume work.
bAllocate = true;
}
L'esempio di codice completo è riportato di seguito:
Imports System
Imports System.Collections.Generic
Imports System.Threading
Imports Microsoft.VisualBasic
Class Program
' Variables for continual checking in the
' While loop in the WaitForFullGcProc method.
Private Shared checkForNotify As Boolean = False
' Variable for suspending work
' (such as servicing allocated server requests)
' after a notification is received and then
' resuming allocation after inducing a garbage collection.
Private Shared bAllocate As Boolean = False
' Variable for ending the example.
Private Shared finalExit As Boolean = False
' Collection for objects that
' simulate the server request workload.
Private Shared load As New List(Of Byte())
Public Shared Sub Main(ByVal args() As String)
Try
' Register for a notification.
GC.RegisterForFullGCNotification(10, 10)
Console.WriteLine("Registered for GC notification.")
bAllocate = True
checkForNotify = True
' Start a thread using WaitForFullGCProc.
Dim thWaitForFullGC As Thread = _
New Thread(New ThreadStart(AddressOf WaitForFullGCProc))
thWaitForFullGC.Start()
' While the thread is checking for notifications in
' WaitForFullGCProc, create objects to simulate a server workload.
Try
Dim lastCollCount As Integer = 0
Dim newCollCount As Integer = 0
While (True)
If bAllocate = True Then
load.Add(New Byte(1000) {})
newCollCount = GC.CollectionCount(2)
If (newCollCount <> lastCollCount) Then
' Show collection count when it increases:
Console.WriteLine("Gen 2 collection count: {0}", _
GC.CollectionCount(2).ToString)
lastCollCount = newCollCount
End If
' For ending the example (arbitrary).
If newCollCount = 500 Then
finalExit = True
checkForNotify = False
bAllocate = False
Exit While
End If
End If
End While
Catch outofMem As OutOfMemoryException
Console.WriteLine("Out of memory.")
End Try
finalExit = True
checkForNotify = False
GC.CancelFullGCNotification()
Catch invalidOp As InvalidOperationException
Console.WriteLine("GC Notifications are not supported while concurrent GC is enabled." _
& vbLf & invalidOp.Message)
End Try
End Sub
Public Shared Sub 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 ful 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.")
End Sub
Public Shared Sub OnFullGCCompleteEndNotify()
' Method that informs the request queuing server
' that this server is ready to accept requests again.
AcceptRequests()
Console.WriteLine("Accepting requests again.")
End Sub
Public Shared Sub WaitForFullGCProc()
While True
' CheckForNotify is set to true and false in Main.
While checkForNotify
' Check for a notification of an approaching collection.
Dim s As GCNotificationStatus = GC.WaitForFullGCApproach
If (s = GCNotificationStatus.Succeeded) Then
Console.WriteLine("GC Notifiction raised.")
OnFullGCApproachNotify()
ElseIf (s = GCNotificationStatus.Canceled) Then
Console.WriteLine("GC Notification cancelled.")
Exit While
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.")
Exit While
End If
' Check for a notification of a completed collection.
s = GC.WaitForFullGCComplete
If (s = GCNotificationStatus.Succeeded) Then
Console.WriteLine("GC Notifiction raised.")
OnFullGCCompleteEndNotify()
ElseIf (s = GCNotificationStatus.Canceled) Then
Console.WriteLine("GC Notification cancelled.")
Exit While
Else
' Could be a time out.
Console.WriteLine("GC Notification not applicable.")
Exit While
End If
End While
Thread.Sleep(500)
' FinalExit is set to true right before
' the main thread cancelled notification.
If finalExit Then
Exit While
End If
End While
End Sub
Private Shared Sub RedirectRequests()
' Code that sends requests
' to other servers.
' Suspend work.
bAllocate = False
End Sub
Private Shared Sub FinishExistingRequests()
' Code that waits a period of time
' for pending requests to finish.
' Clear the simulated workload.
load.Clear()
End Sub
Private Shared Sub AcceptRequests()
' Code that resumes processing
' requests on this server.
' Resume work.
bAllocate = True
End Sub
End Class
using System;
using System.Collections.Generic;
using System.Threading;
namespace GCNotify
{
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 Notifiction 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;
}
}
}
using namespace System;
using namespace System::Collections::Generic;
using namespace System::Threading;
namespace GCNotify
{
ref class Program
{
private:
// 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<array<Byte>^>^ load = gcnew List<array<Byte>^>();
public:
static void Main()
{
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 = gcnew Thread(gcnew 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(gcnew array<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 Notifiction 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;
}
static void FinishExistingRequests()
{
// Code that waits a period of time
// for pending requests to finish.
// Clear the simulated workload.
load->Clear();
}
static void AcceptRequests()
{
// Code that resumes processing
// requests on this server.
// Resume work.
bAllocate = true;
}
};
}
int main()
{
GCNotify::Program::Main();
}