Nota
El acceso a esta página requiere autorización. Puede intentar iniciar sesión o cambiar directorios.
El acceso a esta página requiere autorización. Puede intentar cambiar los directorios.
Hay situaciones en las que una recolección completa de elementos no utilizados realizada por Common Language Runtime puede afectar negativamente al rendimiento. Esto puede suponer un problema, sobre todo con los servidores que procesan grandes volúmenes de solicitudes; en este caso, una recolección de elementos no utilizados de larga duración puede dar lugar a que se agote el tiempo de espera de la solicitud. Para evitar que se produzca una recolección completa de elementos no utilizados en un momento crítico, existe la posibilidad de recibir una notificación de que se va a producir en breve dicha recolección de modo que se podrá redirigir la carga de trabajo a otra instancia del servidor. También se puede inducir una recolección, siempre que la instancia del servidor actual no necesite procesar solicitudes.
![]() |
---|
Esta característica solo está disponible cuando la recolección simultánea de elementos no utilizados está deshabilitada.De forma predeterminada, la recolección simultánea de elementos no utilizados está habilitada, a menos que la ejecución tenga lugar en un entorno hospedado y el host cambie la configuración por usted.La recolección simultánea de elementos no utilizados no está disponible cuando se utiliza la recolección de elementos no utilizados del servidor.Esta característica no admite la recolección simultánea de elementos no utilizados porque se pueden realizar asignaciones de memoria mientras la recolección simultánea de elementos no utilizados está en curso.Para obtener información sobre la forma de deshabilitar la recolección simultánea de elementos no utilizados, vea el valor en tiempo de ejecución de <gcConcurrent>. |
El método RegisterForFullGCNotification se registra para que se cree una notificación cuando el motor en tiempo de ejecución perciba que se aproxima una recolección completa de elementos no utilizados. Esta notificación consta de dos partes: la parte en la que se indica cuándo se aproxima la recolección completa de elementos no utilizados y la parte en la que se indica cuándo se completa dicha recolección.
Para determinar cuándo se genera una notificación, utilice los métodos WaitForFullGCComplete y WaitForFullGCApproach. Normalmente, estos métodos se utilizan en un bucle while para obtener una enumeración GCNotificationStatus sin interrupciones que muestre el estado de la notificación. Si ese valor es Succeeded, puede hacer lo siguiente:
En respuesta a una notificación obtenida con el método WaitForFullGCApproach, puede redirigir la carga de trabajo y posiblemente inducir por sí mismo una recolección.
En respuesta a una notificación obtenida con el método WaitForFullGCComplete, puede habilitar la instancia del servidor actual para que procese las solicitudes de nuevo. También puede recopilar información. Por ejemplo, puede utilizar el método CollectionCount para registrar el número de recolecciones.
Los métodos WaitForFullGCComplete y WaitForFullGCApproach están diseñados para trabajar juntos. Si se utiliza un método sin el otro pueden producirse resultados indeterminados.
Recolección completa de elementos no utilizados
El motor en tiempo de ejecución desencadena una recolección completa de elementos no utilizados en las situaciones siguientes:
Se ha promovido bastante cantidad de memoria a la generación 2 para producir la recolección de generación 2 siguiente.
Se ha promovido una gran cantidad de memoria a un montón de objetos grandes para desencadenar la recolección de generación 2 siguiente.
Una recolección de generación 1 se ha elevado a una recolección de generación 2 por otros factores.
Los umbrales que especifique en el método RegisterForFullGCNotification se aplicarán en los dos primeros escenarios. Sin embargo, en el primer escenario, no siempre recibirá la notificación en el tiempo proporcional a los valores de umbral que especificó por dos motivos:
El motor en tiempo de ejecución no comprueba cada asignación de objetos pequeños (por motivos de rendimiento).
Solo las recolecciones de generación 1 promueven la memoria a la generación 2.
El tercer escenario también contribuye a la incertidumbre respecto a cuándo se recibirá la notificación. Aunque no es una garantía, demuestra que es un mecanismo útil para mitigar los efectos de una recolección completa de elementos no utilizados inoportuna al redirigir las solicitudes durante este período de tiempo o al inducir por sí mismo la recolección cuando puede resultar más oportuna.
Parámetros de umbral de notificación
El método RegisterForFullGCNotification tiene dos parámetros para especificar los valores de umbral de los objetos de generación 2 y el montón de objetos grandes. Cuando estos valores se satisfacen, deberá emitirse una notificación de recolección de elementos no utilizados. En la tabla siguiente se describen estos parámetros.
Parámetro |
Descripción |
---|---|
maxGenerationThreshold |
Número comprendido entre 1 y 99 que especifica cuándo debe emitirse la notificación conforme a los objetos promovidos a la generación 2. |
largeObjectHeapThreshold |
Número comprendido entre 1 y 99 que especifica cuándo debe emitirse la notificación conforme a los objetos asignados al montón de objetos grandes. |
Si especifica un valor demasiado alto, existe una gran probabilidad de que reciba una notificación, pero es posible que tenga que esperar largo tiempo antes de que el motor en tiempo de ejecución produzca la recolección. Si induce la recolección por sí mismo, puede reclamar más objetos de los que reclamaría si el motor en tiempo de ejecución desencadenara la recolección.
Si especifica un valor demasiado bajo, el motor en tiempo de ejecución puede desencadenar la recolección antes de tener suficiente tiempo para emitir una notificación.
Ejemplo
Descripción
En el ejemplo siguiente, un grupo de servidores da servicio a solicitudes web entrantes. Para simular la carga de trabajo del procesamiento de las solicitudes, las matrices de bytes se agregan a una colección List<T>. Cada servidor realiza el registro de una notificación de recolección de elementos no utilizados y, a continuación, inicia un subproceso en el método de usuario WaitForFullGCProc para supervisar de forma continuada la enumeración GCNotificationStatus devuelta por los métodos WaitForFullGCComplete y WaitForFullGCApproach.
Los métodos WaitForFullGCComplete y WaitForFullGCApproach llaman a sus respectivos métodos de usuario de control de eventos cuando se emite una notificación:
OnFullGCApproachNotify
Este método llama al método de usuario RedirectRequests, que indica al servidor de cola de solicitudes que deje de enviar solicitudes al servidor. Esto se simula al establecer la variable bAllocate de nivel de clase en false para que no se asignen más objetos.
A continuación, se llama al método de usuario FinishExistingRequests para finalizar el procesamiento de las solicitudes del servidor pendientes. Para simular esto, se borra la colección List<T>.
Finalmente, se induce una recolección de elementos no utilizados porque la carga de trabajo es ligera.
OnFullGCCompleteNotify
Este método llama al método de usuario AcceptRequests para reanudar la aceptación de solicitudes, pues el servidor ya no es susceptible de que se produzca una recolección completa de elementos no utilizados. Esta acción se simula estableciendo la variable bAllocate en true para que los objetos puedan agregarse de nuevo a la colección List<T>.
El código siguiente contiene el método Main del ejemplo.
' 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);
}
}
El código siguiente contiene el método de usuario WaitForFullGCProc, que contiene un bucle while continuo para comprobar las notificaciones de la recolección de elementos no utilizados.
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;
}
}
}
El código siguiente contiene el método OnFullGCApproachNotify cuando se llama desde el
método 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.");
}
El código siguiente contiene el método OnFullGCApproachComplete cuando se llama desde el
método 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.");
}
El código siguiente contiene los métodos de usuario a los que se llama desde los métodos OnFullGCCompleteNotify y OnFullGCApproachNotify. Los métodos de usuario redirigen las solicitudes, finalizan las solicitudes existentes y, a continuación, reanudan las solicitudes una vez que tiene lugar la recolección completa de elementos no utilizados.
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;
}
El ejemplo de código completo es el siguiente:
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();
}