2010-05-17 20 views
9

Estoy escribiendo un programa para formatear 100s de datos de cadena de MB (cerca de un concierto) en xml == y estoy obligado a devolverlo como respuesta a una solicitud de HTTP (GET).cadena muy grande en la memoria

estoy usando un StringWriter/XmlWriter para construir un XML de los registros de un bucle devolviendo el

using (StringWriter writer = new StringWriter()) 
using (writer = XmlWriter.Create(writer, settings)) //where settings are the xml props 

writer.ToString() 

durante las pruebas vi unas cuantas --out de la memoria exceptions-- y bastante ni idea de cómo para encontrar una solución? ¿Tienen alguna sugerencia para una entrega optimizada de la respuesta?

¿hay una forma eficiente de memoria de codificar los datos? o tal vez fragmentar los datos - No puedo pensar en cómo devolverlo sin la construcción de todo el asunto en un objeto de cadena enorme

gracias

- algunas aclaraciones - esto es un ASP .net webservices app sobre un enlace de gigabit ethernet como lo señaló josh. No estoy muy familiarizado con eso, por lo que todavía es una curva de aprendizaje.

estoy usando XMLWriter para crear el XML y crear una cadena de ella usando cuerdas

algunas estadísticas - tamaño xml = respuesta de alrededor de 385 megas (mi tamaño de los datos crecerán muy rápidamente a mucho más que esto)

cadena tamaño del objeto según los cálculos de un perfilador de memoria = alcanzó un máximo de 605MB

y gracias a todos los que respondieron ...

+9

1 GB de XML como una respuesta HTTP? De Verdad? –

+1

Esto suena como una mala idea. –

+0

Estoy tentado de decir "tira algo de hardware" (bromeando). 500 MB (o 350 MB o 1 GB) por cliente no es escalable. Tal vez podrías arrojar más luz sobre XML que estás generando. Esto http://msdn.microsoft.com/en-us/library/aa528818.aspx podría ayudar. – PRR

Respuesta

4

¿No puede simplemente transmitir la respuesta al cliente? XmlWriter no requiere que su flujo subyacente se almacene en la memoria. Si es ASP.NET puede usar Response.OutputStream o si es WCF, puede usar response streaming.

+0

Josh, este es un proyecto de servicios web - solicitudes de clientes vía GET al método web - siendo nuevo en soluciones de Microsoft, no estoy seguro si es posible y cómo – bushman

+0

Probablemente no sea posible con servicios web ASMX y si eso es lo que estás usando, sugeriría que te muevas a WCF ahora antes de que sea demasiado difícil de rediseñar. Ya te has encontrado con una de las limitaciones de ASMX y hay muchas otras que no solo se limitan al rendimiento. Pero con WCF puede devolver un objeto Stream y dividir los datos en un fragmento para la persona que llama. Todo está incorporado. – Josh

+0

gracias josh !. grandes aportes de todos pero marcarán esto como la respuesta apropiada. – bushman

0

Vas a tener que devolver cada registro (o un pequeño grupo de rec ords) en sus propios GET individuales.

5

Utilice XmlTextWriter envuelto alrededor de Reponse.OutputStream para enviar el XML al cliente y periódicamente descargue la respuesta. De esta forma, nunca tendrá que tener más de unos pocos mb en la memoria al mismo tiempo (al menos para enviarlos al cliente).

+0

Parece que está ensamblando el XML utilizando la manipulación de cadenas. – SLaks

+1

@SLaks, Parece que podría estar haciendo algo ya que realmente no dijo nada. –

+0

+1. O incluso envuelve el 'XmlTextWriter' alrededor de un' GZipStream' envuelto alrededor de 'Response.OutputStream'. – Steven

1

HTTP get for 1 gig? ¡eso es mucho! Tal vez deberías reconsiderar. Al menos gziping la salida podría ayudar.

+1

Gzipping no ayudará si todavía está creando el XML de esta manera. El problema no está en la transferencia de datos, sino en el hecho de que está siendo almacenado en la memoria antes de ser enviado. Y no hay límite práctico para un HTTP GET. Sobre todo teniendo en cuenta que puede reanudar las descargas interrumpidas y no tenemos idea de qué tipo de red lo está enviando. ¡Podría ser un ethernet de gigabit! – Josh

1

No debe crear XML utilizando la manipulación de cadenas.

su lugar, debe utilizar los XmlTextWriter, XmlDocument, o (en .Net 3.5) XElement clases para construir un árbol XML en la memoria, y luego escribir directamente a Response.OutputStream utilizando un XmlTextWriter.

Escribir directamente en un XmlTextWriter que se envuelve Response.OutputStream será más eficiente (nunca tendrá un árbol de elementos completo en la memoria a la vez), pero será algo más complicado.

Al hacerlo de esta manera, nunca tendrá una sola cadena (o matriz) que contenga todo el objeto, y por lo tanto, deberá evitar OutOfMemoryExceptions.

+1

XmlDocument y XElement mostrarán los mismos (en realidad peores) problemas de memoria que la manipulación de cadenas. Crear una estructura XML tan grande solo se puede hacer con la API XmlWriter. – Josh

+1

Aún puede obtener excepciones de memoria insuficiente si no tiene suficiente memoria contigua. Cambiar el enfoque para escribir en una secuencia parece más razonable. –

+0

@Josh: No. Solo 'String' y' Array' asignarán grandes bloques de _contiguous_ memory. – SLaks

1

Tuve un problema similar, espero que esto ayude a alguien. Mi código inicial fue:

var serializer = new XmlSerializer(type); 
string xmlString; 

using (var writer = new StringWriter()) 
{ 
    serializer.Serialize(writer, objectData, sn); // OutOfMemoryException here 
    xmlString = writer.ToString(); 
} 

terminé replaceing StringWriter con MemoryStream y esto resuelve mi problema

using (var mem = new MemoryStream()) 
{ 
    serializer.Serialize(mem, objectData, sn); 
    xmlString = Encoding.UTF8.GetString(mem.ToArray()); 
} 
Cuestiones relacionadas