¿Le resultó útil esta página?
Sus comentarios sobre este contenido son muy importantes. Háganos saber su opinión.
¿Tiene comentarios adicionales?
Caracteres restantes: 1500
Exportar (0) Imprimir
Expandir todo
Este artículo se tradujo de forma manual. Mueva el puntero sobre las frases del artículo para ver el texto original. Más información.
Traducción
Original

Notificaciones de recolección de elementos no utilizados

Hay situaciones en las que una recolección de elementos no utilizados completa (es decir, una recolección de generación 2) 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 de elementos no utilizados completa 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.

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 de elementos no utilizados completa. Esta notificación consta de dos partes: la parte en la que se indica cuándo se aproxima la recolección de elementos no utilizados completa y la parte en la que se indica cuándo se completa dicha recolección.

Nota de precaución Precaución

Sólo bloqueando recolecciones de elementos no utilizados active las notificaciones. Cuando se habilita el elemento de configuración de <gcConcurrent> , las recolecciones de elementos no utilizados en segundo plano no iniciará notificaciones.

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.

El motor en tiempo de ejecución desencadena una recolección de elementos no utilizados completa 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 de elementos no utilizados completa 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.

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.

Cc713687.collapse_all(es-es,VS.110).gifDescripció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 de elementos no utilizados completa. 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.


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 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;

        }
    }
}


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 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;
        }
    }

}


El código siguiente contiene el método OnFullGCApproachNotify cuando se llama desde el

Método WaitForFullGCProc.


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 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 de elementos no utilizados completa.


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;

}


El ejemplo de código completo es el siguiente:


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 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;

        }
    }
}


Adiciones de comunidad

AGREGAR
Mostrar:
© 2015 Microsoft