Solucionar problemas de falta de memoria (System.OutOfMemoryException) en ASP.NET

Este artículo le ayuda a solucionar errores de memoria fuera de la ASP.NET.

Versión del producto original:   ASP.NET
Número KB original:   2020006

Síntomas

Uno de los problemas más comunes que vemos en los Servicios de soporte al cliente de Microsoft son OutOfMemoryException los escenarios. Por lo tanto, hemos reunido una colección de recursos para ayudar a solucionar problemas e identificar la causa de los problemas de memoria.

Antes de cubrir los detalles de la solución de problemas, es importante comprender OutOfMemoryException las causas de este problema. Al contrario de lo que muchos desarrolladores creen, la cantidad de RAM que se instala no afecta a la posibilidad de un OutOfMemoryException . Un sistema operativo de 32 bits puede solucionar 4 GB de espacio de direcciones virtual, independientemente de la cantidad de memoria física instalada en el cuadro. De ese total, 2 GB están reservados para el sistema operativo (memoria en modo kernel) y 2 GB se asignan a procesos de modo de usuario. Los 2 GB asignados para la memoria en modo kernel se comparten entre todos los procesos, pero cada proceso obtiene sus propios 2 GB de espacio de direcciones en modo de usuario. Todo supone que no se está ejecutando con el /3gb modificador habilitado.

Cuando una aplicación necesita usar memoria, se reserva un fragmento del espacio de direcciones virtual y, a continuación, confirma la memoria de ese fragmento. Es exactamente lo que hace .NET Framework recolector de elementos no utilizados (GC) cuando necesita memoria para aumentar los montón administrados. Cuando el GC necesita un nuevo segmento para el montón de objetos pequeños (donde residen objetos menores de 85 KB), realiza una asignación de 64 MB. Cuando necesita un nuevo segmento para el montón de objetos de gran tamaño, realiza una asignación de 16 MB. Estas asignaciones grandes deben satisfacerse a partir de bloques contiguos de los 2 GB de espacio de direcciones con los que debe trabajar el proceso. Si el sistema operativo no puede satisfacer la solicitud del GC de un bloque contiguo de memoria, se produce System.OutOfMemoryException un (OOM).

Nota

Un proceso de 32 bits que se ejecuta en un sistema operativo de 64 bits puede solucionar 4 GB de memoria en modo de usuario y un proceso de 64 bits que se ejecuta en un sistema operativo de 64 bits puede solucionar 8 TB de memoria en modo de usuario, por lo que no es probable que una OOM en un sistema operativo de 64 bits. Es posible experimentar una OOM en un proceso de 32 bits que se ejecuta en un sistema operativo de 64 bits, pero normalmente no se produce hasta que el proceso usa cerca de 3 GB de bytes privados.

Hay dos razones por las que es posible que vea una condición OOM.

  1. El proceso usa mucha memoria (normalmente más de 800 MB en un entorno de 32 bits).
  2. El espacio de direcciones virtual está fragmentado, lo que reduce la probabilidad de que una asignación grande y contigua tenga éxito.

También es posible ver una condición OOM debido a una combinación de 1 y 2. Para obtener más información, vea Troubleshooting System.OutOfMemoryExceptions in ASP.NET.

Cuando se produce una OOM, es posible que observe uno o varios de los síntomas siguientes:

  • La aplicación se bloquea. Para obtener más información, vea Quién es este tipo de OutOfMemoryy ¿por qué hace que mi proceso se desplome cuando me queda mucha memoria? .

  • La aplicación puede experimentar una memoria alta según lo indicado por el Administrador de tareas o el Monitor de rendimiento.

  • Las solicitudes pueden tardar mucho tiempo en procesarse.

    En Internet Information Services (IIS) 7, puede usar Troubleshooting Failed Requests Using Tracing in IIS 7 para solucionar las solicitudes de larga ejecución.

  • Los usuarios pueden informar de un mensaje de error en la aplicación debido a la OOM.

Cuando se trata de determinar la causa de una condición OOM, realmente está trabajando para determinar la causa de una situación de memoria alta o un espacio de direcciones fragmentado. Aunque no podemos documentar todas las causas posibles de estas situaciones, hay algunas causas comunes que vemos con regularidad.

En la siguiente información se describen las causas comunes de las condiciones de OOM y las resoluciones para resolver cada una de estas causas.

Concatenación de cadenas

Las cadenas de una aplicación administrada (una aplicación escrita mediante el .NET Framework) son inmutables. Cuando se asigna un nuevo valor a una cadena, se realiza una copia de la cadena existente. Y el nuevo valor se asigna a la nueva cadena. Por lo general, no causa ningún problema. Sin embargo, cuando se concatena un gran número de cadenas, termina causando muchas más asignaciones de cadenas de las que un desarrollador puede comprender. Y puede provocar el crecimiento de la memoria y las condiciones de OOM.

Para evitar OOM debido a la concatenación de cadenas, asegúrese de que está usando la StringBuilder clase. Para obtener más información, vea How to improve string concatenation performance in Visual C#.

Fragmentación en el montón administrado

El recolector de elementos no utilizados (GC) de una aplicación administrada compacta los montón para reducir la cantidad de fragmentación. Sin embargo, es posible anclar objetos en una aplicación administrada. Los objetos anclados no se pueden mover durante la compactación del montón. Al hacerlo, se cambiaría la dirección en la que se encuentra el objeto. Si una aplicación ancla un gran número de objetos y/o ancla objetos durante mucho tiempo, puede provocar fragmentación en el montón administrado. Puede provocar que el GC crezca el montón administrado con más frecuencia y cause una condición OOM.

Hemos trabajado para minimizar las condiciones de OOM debido a la fijación desde la .NET Framework 1.0. Se han realizado mejoras incrementales en cada versión. Sin embargo, todavía hay patrones de diseño que puede implementar que serán beneficiosos si necesita anclar objetos.

Fragmentación en el espacio dirección virtual (VA)

Cada proceso tiene asignada una cierta cantidad de memoria y esa memoria representa el espacio VA para el proceso. Si el espacio va se fragmenta, aumenta la probabilidad de que el GC no pueda obtener un bloque grande de memoria contigua para aumentar los montón administrados. Y puede dar lugar a una condición OOM.

La fragmentación en el espacio VA suele deberse a uno o varios de los siguientes escenarios:

  • Cargar los mismos ensamblados en varios dominios de aplicación.

    Si necesita usar un ensamblado en más de una aplicación que se ejecute en el mismo grupo de aplicaciones, asigne un nombre de seguridad al ensamblado e instállo en la GAC. Al hacerlo, se asegura de que el ensamblado solo se carga en el proceso una vez.

  • Ejecución de una aplicación en producción con el atributo debug del <compilation> elemento establecido en true .

    • El atributo debug del <compilation> elemento debe estar en false producción.
    • Puede usar la configuración <deploy retail="true" /> para asegurarse de que la depuración siempre está deshabilitada en el producto. Para obtener más información, vea deployment Element (ASP.NET Configuración Schema).
  • El uso de scripts en eXtensible Style sheet Language (XSL) transforma o crea XmlSerializers .

    En este caso, los ensamblados dinámicos causados por scripts de transformación de lenguaje de hoja de estilos extensibles (XSLT) o XmlSerializers .

Devolver grandes conjuntos de datos

Al usar datos de una base de datos u otro origen de datos, es importante limitar la cantidad de datos devueltos. Por ejemplo, almacenar en caché un resultado de consulta que devuelve una tabla de base de datos completa para evitar el costo de recuperar partes de datos de la base de datos cuando sea necesario no es un buen enfoque. Si lo hace, puede causar memoria alta fácilmente y provocar una condición OOM. Permitir que un usuario inicie una consulta similar es otra forma común de crear una situación de memoria alta. Por ejemplo, devuelva todos los empleados de una empresa o todos los clientes del estado de Texas con un apellido que comience por la letra S.

Limite siempre la cantidad de datos que se pueden devolver desde una base de datos. No permita consultas como porque, a continuación, no tiene control sobre la cantidad de datos que se SELECT * FROM. . . muestran en la página.

Es igualmente importante asegurarse de que no se muestra un resultado de datos grande en elementos de la interfaz de usuario, como el control GridView. Además de la memoria necesaria para los datos devueltos, también consumirás grandes cantidades de datos en cadenas y en elementos de interfaz de usuario necesarios para representar los resultados. Al implementar la paginación y validar la entrada para que no se devuelvan grandes conjuntos de datos, puede evitar este problema.

Ejecutar en un entorno de producción con seguimiento habilitado

ASP.NET seguimiento es una característica eficaz para solucionar problemas de aplicaciones. Pero nunca se debe dejar en un entorno de producción. ASP.NET seguimiento usa estructuras de datos como almacenar información de seguimiento y, con el tiempo, pueden provocar una condición de memoria alta que puede provocar DataTables OOM.

El seguimiento debe deshabilitarse en un entorno de producción. Puede hacerlo estableciendo el enabled atributo del elemento en false en el <trace> web.config archivo. Habilitar la implementación comercial mediante <deploy retail="true" /> el uso también deshabilita el seguimiento en las aplicaciones.

Pérdida de recursos nativos

Muchos recursos administrados también usarán recursos nativos. Dado que el GC no limpia los recursos nativos, un desarrollador es responsable de implementar y llamar al método Dispose para limpiar los recursos nativos. Si usa un tipo que implementa la interfaz y no llama al método, corre el riesgo de perder recursos nativos y provocar una condición IDisposable Dispose OOM.

Estos objetos deben implementar la interfaz y debe llamar al método en iDisposable estos objetos cuando ya no los Dispose necesite.