So glaube ich nicht, das Problem zu SelectMany
oder auch reaktiven Erweiterungen notwendigerweise zurückzuführen ist. Es sieht so aus, als ob WriteableBitmap
nicht verwalteten Speicher verwendet: source code. Ich glaube, das Problem ist, dass Sie in sehr schneller Folge eine Menge relativ kleiner verwalteter Objekte erstellen, die viel mehr nicht verwalteten Speicher belegen. Vom MSDN:
Wenn ein kleines verwaltete Objekt eine große Menge an nicht verwalteten Speicher zuweist, nimmt die Laufzeit berücksichtigt nur den verwalteten Speicher und unterschätzt damit die Dringlichkeit der Planung der Garbage Collection.
Aber wir können die Garbage Collector Hinweise geben, indem sie die GC.AddMemoryPressure
und GC.RemoveMemoryPressure
Funktionen. Dies wird dem GC helfen, seine Planung zu verbessern. Bevor wir das tun können, müssen wir eine Vorstellung davon haben, wie viel nicht gemanagter Speicher zugewiesen wird. Ich glaube, dass der nicht verwaltete Speicher verwendet wird, um das Pixelarray zu speichern, so dass ich denke, eine gute Schätzung ist die Pixelbreite mal die Pixelhöhe mal die Anzahl der Bits in jedem Kanal multipliziert mit der Anzahl der Kanäle. Von der MSDN sieht es aus, als ob es 32 Bits (4 Bytes) pro Kanal und 4 Kanäle gibt.
lief ich einige Tests Code ähnlich dem folgenden verwenden und haben wirklich gute Ergebnisse:
var processed =
Enumerable
.Range(0, 100)
.Select(_ => new WriteableBitmap(
800,
600,
96,
96,
PixelFormats.Bgr24,
new BitmapPalette(new List<Color>() { new Color() })))
.Select(x => new { Bitmap = x, ByteSize = x.PixelWidth * x.PixelHeight * 4 * 4)
.ToObservable()
.Do(x => GC.AddMemoryPressure(x.ByteSize))
.SelectMany(x => DoSomethingAsync(x.Bitmap));
processed
.Subscribe(x => GC.RemoveMemoryPressure(x.ByteSize));
Allerdings, wenn Ihre Quelle schneller veröffentlicht Bitmaps, als Sie sie Sie werden dann behandeln können immer noch Probleme haben,. Der Gegendruck bewirkt, dass der Speicher schneller zugewiesen wird als freigegeben werden kann.
Ehrlich gesagt, haben Sie wirklich Bitmaps zu Ihnen geschoben? Ich habe keine Ahnung, wie Ihr aktuelles Programm aussieht, aber in Ihrem Beispielcode ist das ein Pull-basiertes System. Wenn es sich um ein Pull-basiertes System handelt, haben Sie in Betracht gezogen PLINQ? PLINQ ist großartig für diese Art von Ding; es gibt Ihnen wirklich gute Kontrolle über Nebenläufigkeit und Sie müssen sich nicht über Gegendruck sorgen.
Wenn Sie ‚Writeablebitmap‘ suchen um und ‚Speicherleck‘, gibt es eine Menge von Plakaten das gleiche Problem auftritt, und ein Mangel an guten Lösungen. Wenn Sie die WriteableBitmap nicht verwenden müssen (dh wenn Sie nicht mit der Benutzeroberfläche arbeiten), würde ich die Bitmap-Klasse verwenden und Ihren Code ändern, um die Bitmap mit einer using-Anweisung in SelectMany zu erstellen/disponieren. – Andrew
@ Andrew - Es könnte mit dem Problem zusammenhängen, das du beschreibst. Ich denke, es hängt von der Version von .NET ab, die das OP verwendet. Es scheint, dass das Speicherproblem in 4.0 angesprochen wurde. In meinen Tests mit .NET 4.5 wächst der Speicher schnell außer Kontrolle, aber es wird schließlich Müll gesammelt, so dass ich glaube nicht, dass es ein Speicherleck ist. –
@JasonBoyd - Interessant, mit 4.5, konnte ich die maximale Speicherzuweisung (2 GB) blasen und den Prozess abstürzen. Ein Aufruf von GC.Collect() nachdem die Bitmap nicht in meinem modifizierten Code enthalten war, hat es auch nicht verhindert (obwohl ich niemals in Erwägung ziehen würde, solch einen GC-Call in Produktion zu setzen) – Andrew