2009-07-10 11 views
0

Dies ist ein C# -Problem. Ich habe zu einer bestimmten Zeit ein großes Objekt im Gedächtnis. Ich möchte es in eine Datei serialisieren. Es gibt zwei Schritte, um es zu tun. 1. Ich muss das Objekt in CSV-String ändern. 2. Ich muss die CSV-Zeichenfolge serialisieren.Wie kann der Speicherverbrauch reduziert werden?

Ich habe ein Dienstprogramm, das Zeichenfolgen an einen MemoryStream anhängen kann. Ich benutze dieses Hilfsprogramm, um das große Objekt in eine CSV-Zeichenfolge (in einem großen Stamm von MemoryStream) zu konvertieren. Nachdem das große Objekt in einen MemoryStream konvertiert wurde, erstelle ich einen StreamReader des MemoryStream und rufe seine Methode StreamReader.ReadToEnd() auf, um den MemoryStream in eine (lange) Zeichenkette umzuwandeln. Dann rufe ich info.AddValue ("BigObject", String) auf; um die Zeichenfolge zu serialisieren.

Wie man sehen kann, werde ich in der Erinnerung tatsächlich drei Kopien des großen Objekts halten. Der erste ist das Objekt selbst, der zweite ist der MemoryStream, der den csv-String enthält, und der dritte ist der String, der eigentlich ein redundanter MemoryStream ist.

Gibt es eine Möglichkeit, den Speicherverbrauch in diesem Verfahren zu reduzieren? Es scheint, dass, wenn nicht MemoryStream, ich sowieso einen StringBuilder verwenden muss, um die CSV-Zeichenfolge des großen Objekts zu halten, und ich muss StringBuilder.ToString() aufrufen, um die letzte Zeichenfolge zu erhalten. Dann werden die letzte Zeichenfolge und der StringBuilder im Speicher nebeneinander vorhanden sein und die gleiche Menge an Speicher verbrauchen wie derzeit der MemoryStream und die Zeichenfolge.

Jede Idee ist willkommen. Vielen Dank.

+0

Ich glaube nicht, dass 'StringBuilder.ToString()' tatsächlich eine separat zugewiesene Zeichenfolge zurückgibt, so dass Sie mindestens eine Kopie speichern würde. – jerryjvl

+0

Wie groß sind diese großen Objekte übrigens? ... wenn es über die magische (aktuelle) Grenze von 85KB hinausgeht, haben Sie möglicherweise andere Probleme, die sich auf die Speicherfragmentierung beziehen. – jerryjvl

+0

jerryvl, du hast Recht, dass es keine neue Zeichenfolge kopiert. Die Zeichenfolge wird jedoch intern neu zugewiesen, wenn sie ihr Limit überschreitet, indem ein Doubling-Algorithmus verwendet wird. Also, wenn ich meine Mathe richtig verstanden habe, wird es in der Lage sein, doppelt so viel Speicher zuzuweisen wie die Zeichenfolge, die es zurückgibt, in Stücken verschiedener Größen. –

Antwort

1

Wenn Sie sich Sorgen über die Spitzenspeicherauslastung machen, können Sie eine Speicherbereinigung manuell erzwingen, nachdem Sie mit dem ORIGNAL-Objekt fertig sind, und dann erneut, nachdem Sie den Speicherstream beendet haben.

(Lassen Sie mich nur darauf hinweisen, dass, während es einige Fälle, in denen die Kontrolle über die Garbage Collection, die nötig ist, es ist generell eine schlechte Idee. In der Regel ist es besser, nichts zu unternehmen, zu gegebener Zeit gesammelt bekommen.)

+0

Die Implementierung der IDisposable-Schnittstelle oder eines Dekonstruktors wird nicht helfen, wenn drei Kopien des Objekts gleichzeitig auf dem Heap zugeordnet werden. –

+0

Eigentlich sagt dieser Artikel es ziemlich gut. Wenn Sie jemals GC.Collect() aufgerufen haben; dann lies es dir durch. http://lyontamers.com/blogs/jimlyon/archive/2008/08/29/garbage-collection-finalizers-and-dispose-what-every-c-programmer-should-know.aspx –

+0

Nein, aber alles ausgleichen Verweise und das Aufrufen des GC führen dazu, dass der Speicher sofort freigegeben wird. Ich werde den Artikel sehen, danke. –

0

Sie müssen keine eigene Serialisierung implementieren. Sie können es dem .NET-Framework überlassen. Ein guter Startpunkt kann here gefunden werden.

1

Geben Sie Folgendes ein.

 public void SerializeToFile<T>(T target, string filename) 
     { 
      XmlSerializer serializer = new XmlSerializer(typeof (T)); 

      using (FileStream stream = new FileStream(filename, FileMode.Create, FileAccess.Write)) 
      { 
       serializer.Serialize(stream, target); 
      } 
     } 

Edit: Angenommen, Sie Ihr Objekt erhalten können ISerializable zu implementieren und Ihre Nützlichkeit in die GetObjectData Methode zu binden.

Edit2: Verpasste den CSV-Teil. Eklig. Versuchen Sie, nach der Serialisierung ein XSLT für das XML zu verwenden.

Link zu einem article über das Konvertieren von Xml zu CSV über eine XSLT.

0

Um welche Art von Daten handelt es sich? Wenn es sich um Textdaten handelt, könnten Sie eine memische Komprimierung verwenden und auf diese Weise viel Speicher sparen.

+0

Willst du wetten, dass es eine Tabelle ist? –

0

Anstatt den Zwischenschritt des Konvertierens des Objekts in eine CSV-Zeichenfolge auszuführen, sollten Sie versuchen, das Objekt in die Datei zu schreiben, während Sie es serialisieren. Verwenden Sie einfach einen Dateistream anstelle von MemoryStream, wenn Sie die CSV-Datei erstellen. Besser noch, erstellen Sie eine SerializeToStream-Methode für Ihr Objekt, die einen beliebigen Stream als Parameter verwendet.

Verwandte Themen