2010-04-22 12 views
5

La situación es que estoy realizando una llamada WCF a un servidor remoto que devuelve un documento XML como una cadena.Cómo maximizar el bloque contiguo más grande de memoria en el montón de objetos grandes

mayoría de las veces este valor de retorno es de unos pocos K, a veces unas pocas docenas K, muy de vez en cuando unos pocos cientos de K, pero muy rara vez podría ser de varios megabytes (primer problema es que no hay manera de que yo sé)

Son estas raras ocasiones las que están causando dolor. Consigo un seguimiento de pila que comienza:

System.OutOfMemoryException: Exception of type 'System.OutOfMemoryException' was thrown. 
    at System.Xml.BufferBuilder.AddBuffer() 
    at System.Xml.BufferBuilder.AppendHelper(Char* pSource, Int32 count) 
    at System.Xml.BufferBuilder.Append(Char[] value, Int32 start, Int32 count) 
    at System.Xml.XmlTextReaderImpl.ParseText() 
    at System.Xml.XmlTextReaderImpl.ParseElementContent() 
    at System.Xml.XmlTextReaderImpl.Read() 
    at System.Xml.XmlTextReader.Read() 
    at System.Xml.XmlReader.ReadElementString() 
    at Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationReaderMDRQuery.Read2_getMarketDataResponse() 
    at Microsoft.Xml.Serialization.GeneratedAssembly.ArrayOfObjectSerializer2.Deserialize(XmlSerializationReader reader) 
    at System.Xml.Serialization.XmlSerializer.Deserialize(XmlReader xmlReader, String encodingStyle, XmlDeserializationEvents events) 
    at System.Xml.Serialization.XmlSerializer.Deserialize(XmlReader xmlReader, String encodingStyle) 
    at System.Web.Services.Protocols.SoapHttpClientProtocol.ReadResponse(SoapClientMessage message, WebResponse response, Stream responseStream, Boolean asyncCall) 
    at System.Web.Services.Protocols.SoapHttpClientProtocol.Invoke(String methodName, Object[] parameters) 

he leído alrededor y es porque el objeto grande Montón apenas está demasiado fragmentado, por lo que incluso anterior a la llamada con una comprobación rápida para StringBuilder.EnsureCapacity simplemente hace que el OutOfMemoryException se lanzará antes (y debido a que estoy adivinando lo que se necesita, puede que en realidad no necesite tanto que mi chequeo está causando más problemas de los que está resolviendo). Algunos opinions dicen que no hay mucho que pueda hacer al respecto.

Algunas de las preguntas que me he preguntado a mí mismo:

  • utilizan menos memoria - ¿Ha comprobado que no haya fugas? Sí. El uso de memoria aumenta y disminuye, pero no hay un crecimiento fundamental que garantice que esto suceda. Algunas veces falla, tuvo éxito en esa etapa previamente.
  • Transferencia de cantidades más pequeñas No es una opción, este es un servicio de terceros web a través de los cuales no tengo control (o al menos se necesitaría mucho tiempo para resolver, mientras tanto todavía tengo un problema)
  • ¿Puedes hacerle algo al LOH para que sea menos probable que falle? ... ahora este es el curso más fructífero. Es un proceso de 32 bits (tiene que ser por varias razones políticas, técnicas y aburridas) pero normalmente hay cientos de meg free (múltiplos de la cantidad más grande por la que hemos visto fallas).
  • ¿Podemos monitorear el LOH? Utilizando perfmon puedo rastrear el tamaño de los montones, pero no creo que haya una manera de controlar el bloque contiguo de memoria más grande disponible.

Pregunta es: ¿algún consejo o sugerencia para probar?

Respuesta

5

que te pueden revisar la TransferMode propiedad de su unión a ver si cumple con los requisitos para cambiarlo desde su valor por defecto de "amortiguado", de "streaming " o "StreamedResponse".

Además, revise los valores para maxBufferPoolSize y MaxBufferSize. Aumentar el tamaño de los búferes internos utilizados puede ayudar con la utilización de la memoria, especialmente con el procesamiento de mensajes grandes.

maxReceivedMessageSize también es probable que ya establece si su recepción de mensajes de gran tamaño, pero yo revisaría ese valor también.

He visto uno de los valores anteriores, si supera el umbral, falla con un mensaje oscuro, relacionado con la memoria. La excepción original en realidad estaba oculta por el mensaje que apareció en mi aplicación.Habilitando WCF Tracing ayudó a diagnosticar el problema y ver el error real - Necesitaba aumentar el valor de una, o más, de las propiedades de enlace anteriores.

No he tenido la sensación de que su publicación está vinculada a su publicación, pero creo que esta configuración es común en las principales. Consulte la documentación de MSDN en basicHttpBinding, por ejemplo.

Si realmente se trata de fragmentación LOH, no hay nada que hacer una vez que se hayan agotado los esfuerzos de sintonización. Puede que se requiera el reciclaje continuo de la aplicación para mitigarlo (odio recomendarlo) pero si ha agotado otros esfuerzos, es posible que se quede con eso.

+0

Cambiar el encuadernado es una buena idea. Lo probaré. Un reciclado continuo fue nuestro último recurso ... – Unsliced

+0

hemos tenido la suerte de mitigar cualquier problema con el gran procesamiento de documentos a través de mejoras de código (aunque poseemos ambos puntos finales) o cambios vinculantes, al menos para ayudarnos a un reciclaje de mantenimiento programado regularmente (debido a parches, lanzamiento de características, etc.). @ La idea de Steven de usar windbg para el análisis de pila también puede generar beneficios. Pruebe http://blogs.msdn.com/tess/ y encontrará buena información de Tess Ferrandez sobre cómo comenzar aquí. Excelentes laboratorios! ¡Buena suerte! –

1

Creo que su problema Podría haber una fuga Asamblea causada por el uso de XmlSerializer y no usar uno de los dos constructores como se indica en este MSDN article:

para aumentar el rendimiento, la infraestructura de serialización XML genera dinámicamente conjuntos a serializar y deserializar tipos especificados . La infraestructura encuentra y reutiliza esos ensambles. Este comportamiento se produce sólo cuando utilizando los siguientes constructores:

XmlSerializer.XmlSerializer (Tipo)

XmlSerializer.XmlSerializer (Tipo, String)

Si utiliza cualquiera de los otros constructores , múltiples se generan las versiones del mismo ensamblaje y nunca se descargó , que da como resultado una pérdida de memoria y un bajo rendimiento.

Agradable, eh. La respuesta es almacenar en caché su XmlSerializer (suponiendo que incluso lo haya creado).

Para averiguarlo realmente, tiene que hacer lo que Tess le indica que haga. Ella es una genio maldita.

1

De ser posible, elegiría un enfoque basado en flujo y usaría un analizador Xml directo solo en combinación, lo que también le proporcionaría un mejor rendimiento.

Si no tiene que usar absolutamente WCF, puede escribir su propia HttpRequest y luego pasar la respuesta al XmlDeserializer y luego analizar la respuesta de esa manera. Podría proporcionarle más control y una mayor comprensión de dónde ocurre realmente el problema. También puede experimentar con un servicio simulado que devuelve documentos muy grandes del tipo que está buscando. Tuvimos muchos dolores de cabeza con la fragmentación de LOH así que realmente siento tu dolor.

Un problema que noté al construir memorias intermedias .NET tiende a duplicar la capacidad cada vez que se llena el búfer, lo que provoca la fragmentación de la memoria ya que para un documento de tamaño 10mb, la memoria debe asignarse en muchos pasos. Si conoce el tamaño de búfer necesario por adelantado, es más eficiente asignarlo de una vez. Entonces, si sabe cuán grande será el documento entrante, puede crear un StringBuilder con exactamente ese tamaño.

2

No puedo resolver ninguno de los problemas específicos de WCF, pero si necesita maximizar el espacio LOH para un proceso de 32 bits, debe hacer la aplicación large address aware y ejecutarla en 64 bits. Un proceso de 32 bits con capacidad de dirección grande podrá abordar todo el espacio de direcciones de 4 GB cuando se ejecute en Windows de 64 bits. Esto le dará una gran cantidad de memoria por encima del espacio de direcciones normalmente utilizado por el proceso.

Cuestiones relacionadas