2010-07-07 7 views
5

Ich habe eine Anwendung geschrieben mit .NET 3.5 SP1, die Bilder von einer externen Site herunterlädt und sie für die Endbenutzer anzeigt. In seltenen Fällen erleben meine Benutzer OutOfMemory-Fehler, weil sie riesige Bilder herunterladen. Manchmal sind die Rohdaten, die mit diesen Bildern verbunden sind, groß, aber häufiger sind die Abmessungen der Bilder groß. Ich realisiere, dass ich vielleicht nie die Tatsache umgehen kann, dass diese OOM-Fehler für bestimmte Bilder ausgelöst werden. Es wäre jedoch SEHR hilfreich, wenn ich irgendwie feststellen könnte, ob das Laden eines bestimmten Bildes zu einem OOM-Problem führen würde, bevor ich versuche, das Bild zu laden.Wie erkennt man, ob das Laden eines Bildes eine OutOfMemory-Ausnahme in .NET auslöst?

Die Daten für die Bilder werden in einen Stream geladen, und dann wird das Bild selbst in ein System.Drawing.Image umgewandelt, indem ein Aufruf von System.Drawing.Image.FromStream (stream) ausgeführt wird. Ich habe nicht die Möglichkeit, diese Bilder zuerst auf der Festplatte zu speichern. Sie müssen über den Speicher geladen werden.

Wenn jemand irgendwelche Tipps oder Vorschläge hat, die mir erlauben würden zu erkennen, dass das Laden eines Bildes zu einer OOM-Ausnahme führen würde, würde ich es sehr schätzen.

+0

"Die Daten für die Bilder werden in einen Stream geladen" ... durch Magie oder wie? – Will

+0

@Will - "lädt Bilder von einer externen Website herunter" –

+0

@Joel, damit er einen Stream erhält, diesen Stream in einen Speicherstream einspeist und diesen Stream dann mit einem Image verwendet? Und er fragt sich, warum ihm die Erinnerung ausgeht? Warum nicht einfach den Original-Stream benutzen und den mittleren Mann ausschneiden? Bin ich der Verrückte? – Will

Antwort

1

OutOfMemory ist eine dieser Ausnahmen, wo Sie nicht viele gute Optionen haben. Alles, was schlüssig vorhersagen würde, dass Sie die Ausnahme erhalten, würde wahrscheinlich nur die Ausnahme generieren.

Ich würde sagen, dass Ihre beste Wette ist, um das Verhalten zu profilieren und erstellen Sie Ihre eigenen prädiktiven Regelsatz oder einfach nur maximale Größen in Ihre Anwendung programmieren. Es ist nicht schön, aber es wird dich dorthin bringen.

1

Sie könnten an dieser Frage und sehen, ob es hilft: How do I reliably get an image dimensions in .NET without loading the image?

Die Idee wäre es nur ein Teil des Gesamtbildes zum Download sein (der Header speziell), so dass Sie die Metadaten lesen kann. Dann können Sie die Information dort verwenden, um zu bestimmen, wie groß das Bild ist, und es davon abhalten, vollständig herunterzuladen, wenn Sie sehen, dass es zu groß ist.

Auf der anderen Seite scheint es, als müssten Sie eine Methode schreiben, um die Binärdatei jedes Dateityps zu zerlegen, den Sie verarbeiten möchten.

+0

Ja, wir haben über diesen Ansatz nachgedacht. Unsere größte Sorge ist immer noch, dass wir keine gute Möglichkeit haben, genau vorherzusagen, wie viel Speicher System.Drawing.Image.FromImage verwenden wird. Wir müssen jeden Bildtyp unterstützen, den .NET nativ unterstützt. Zusätzlich zu der Notwendigkeit, die Binärdatei jedes Dateityps, den .NET unterstützt, zu zerlegen, müssten wir irgendwie eine Methode entwickeln, die genau vorhersagt, wie viel Speicher beim Laden dieser Bilder benötigt wird. Das scheint etwas zu sein, an dem ein ganzes Entwicklerteam monatelang arbeiten könnte! :( – Keith

1

Sie haben ein Huhn-und-Ei-Problem. Um etwas zu erraten, müssen Sie die Größe des Bildes wissen. Sie kennen die Größe erst, nachdem Sie sie geladen haben.

Es ist sowieso nicht wirklich hilfreich. Ob Sie OOM erhalten, hängt davon ab, wie stark der Adressraum des virtuellen Speichers fragmentiert ist. Und das ist nicht einfach in Windows zu finden. Die HeapWalk() API-Funktion ist erforderlich, und das ist eine ungesunde Funktion zu verwenden. Überprüfen Sie das Kleingedruckte in dem MSDN-Bibliotheksartikel für es. Besonders schlecht in einem verwalteten Programm, benutze es nicht.

Beachten Sie, dass diese OOM-Ausnahme nicht die gleiche Art von OOM ist, die Sie erhalten, wenn Sie zu viel verwalteten Speicher verbraucht haben. Es ist tatsächlich eine GDI + -Ausnahme und Sie können sich leicht davon erholen. Fangen Sie einfach die Ausnahme ab und zeigen Sie die Meldung "Sorry, can not do it" an.

Wenn Sie die Größe der Front irgendwie wissen, dann können Sie ziemlich sicher davon ausgehen, dass die Breite * Höhe * 4> 550 MB in einem 32-Bit-Programm nicht funktionieren wird. Diese Grenze sinkt schnell nach einer Weile.

1

Wenn Sie die Bilder von einer externen Site herunterladen und die externe Site den HTTP-Header Content-Length festlegt, können Sie möglicherweise abschätzen, ob das Image in den Arbeitsspeicher passt, bevor Sie den Stream herunterladen. .

+0

Wir bekommen den Inhalt-Länge-Header. Allerdings ist die schiere physische Größe der Daten kein großer Prädiktor für den Speicherbedarf einer Datei. Ich habe Dateien gesehen, die weniger als 5 MB sind, die über 800 MB kauen wenn sie geladen werden, weil ihre Abmessungen so groß sind – Keith

4

Sie können die Klasse MemoryFailPoint verwenden, um nach Speicherverfügbarkeit zu suchen.

Best

+2

Bitte lesen Sie alle, wie das funktioniert, es ist von FAR der beste Weg, um mit großen Speicherzuweisungen in einer "Versuch/fangen" Weise umzugehen. – Spence

+0

Ich werde das untersuchen. Ein kurzer Blick Ich denke, dass es möglicherweise nicht das ist, was ich brauche, da die Dokumentation sagt, dass ich "die Anzahl der Megabyte Speicher angeben muss, die der Vorgang verwenden soll." Das Problem ist, dass ich nicht weiß, wie viel Speicher GDI + benötigt zu verwenden, wenn es das Bild lädt mit System.Drawing.Image.FromStream. – Keith

1

Ich habe bereits mit @Vagaus Antwort stimmte zu, aber ich wollte noch hinzufügen, dass Sie nur die Puffer einmal zuweisen sollten und versuchen Sie es erneut zu verwenden. Wenn Sie ständig einen großen Puffer zuweisen und freigeben, werden Sie aufgrund der Fragmentierung auf dem Heap auf jeden Fall ein OOM-Problem feststellen.

+0

Wir verwenden diese Technik, wenn wir diese iamges herunterladen. Ich bin jedoch ziemlich sicher, dass System.Drawing.Image.FromImage nutzt es eigener interner Puffer, der ohnehin zur Heap-Fragmentierung führt. – Keith

+0

Nennen Sie ALLE Entsorger auf dem GDI-Zeug? Ich wurde bereits zuvor gebrannt. Fast jede kleine Klasse in den GDI + -Bibliotheken benötigt einen Entschuldungsaufruf, um den nicht verwalteten Speicher freizugeben. Vielleicht verlieren Sie dadurch Speicher und verursachen das OOM? – Spence

+0

Ich bin zuversichtlich, dass wir alle unsere Objekte ordnungsgemäß entsorgen. Wir haben Nutzer, die Stunden damit verbringen können, normal große Bilder zu betrachten, und der Speicherbedarf bleibt konstant. Es gibt nur das gelegentliche Bild mit riesigen Dimensionen, das die restliche Erinnerung verschlingt. – Keith

Verwandte Themen