none
Fehler beim laden eines Bild RRS feed

  • Frage

  • Salü alle zusammen

    Ich habe ein Bild, http://de.academic.ru/pictures/dewiki/84/THIERSHEIM.jpg 

    Wenn ich nun dieses Bild mit dem unten stehenden Code laden will, bekomme ich einen Memory Overflow. Weiss jemand, wie ich das verhindern kann?

    Dim bildPfad As String
    bildPfad = "D:/testimage/THIERSHEIM2.jpg"
    Dim Bild2 As Bitmap
    Bild2 = New Bitmap(bildPfad) '<-- Hier MemoryOverflow 

    Vielen lieben Dank für jeden Hinweis
    Gruss Sabrina

    Montag, 20. Dezember 2010 17:38

Antworten

  • Sabrina,

    ich sehe eher, dass du uns hier mal genauer sagen musst, wozu du die Bilder technisch brauchst (Weiterverarbeitung/Darstellung usw ?).
    Denn eine Auflösung von den 7056x9708 ist um Faktor 5-10 zu gross, um zum Beispiel auf gängigen Bildschirmen (1:1) voll darzustellen!
    Denn falls du die Bilder gar nie auf dem Bildschirm anzeigst, dann wäre diese WinForms (GDI+) Bitmap-Klasse evtl hier gar fehl am Platz.

    Und was du mit dem MemoryStream erreichen willst ist mir nicht klar (ist in deinem Code nur ein Umweg, löst eigentliches Problem in keiner Weise).

    PS:
    Dass der Server 4GB hat ist OK, aber wichtig (mind für deine riesigen Bilder) wäre dann noch, dass es besser ein 64-Bit Betriebssystem sein sollte, damit auch wirklich die 4GB voll ausgenützt werden können  (ggf gar mit 64-Bit .NET App).
    Dienstag, 21. Dezember 2010 13:05

Alle Antworten

  • Hallo Sabrina

    Kann ich mit VB2010 und für .NET 4.0 sowie 3.5 compiliert  (unter Win7) nicht reproduzieren.
    Welche .NET und Studio-Versionen nutzt du?
    Versuche dasselbe auch mal in einem frisch erstellten Minimal-Projekt!

    Wenn in deinem System ansonst noch genug Speicher frei ist  (auch für Auslagerungsdatei-Pagefile.sys), dann ist dies uU eher ein Schaden an der Laufzeit-Runtime, insbesondere falls du  in deinem Code irgendwo COM-Interop (ActiveX/OCX) nutzt, oder PINvoke  (Declare / DllImport API) hast, mit Fehlverhalten  (und somit irgend eine Speicher 'corruption' vorliegt).

    Oder dein JPG Bild hat effektiv ungültigen Inhalt, wirkt sich aber 'undefiniert - zufällig' aus...
      (JPG müsste man validieren)

    Teils auch wichtig, aktuelle Grafikkarten-Treiber.
    Montag, 20. Dezember 2010 17:52
  • Kann ich mit VB2010 und für .NET 4.0 sowie 3.5 compiliert  (unter Win7) nicht reproduzieren.
    auch nicht mit VB2008 unter WinXP.
    Das Bild (4MB JPG Datei) zu laden kostet übrigens >200MB Speicher!
    Montag, 20. Dezember 2010 18:54
  • Salü Thomas

    Super vielen Dank für Deine Antwort.

    Wie von Dir empfohlen, habe ich ein Minimalprojekt gemacht. Und schau an, das Teil marschiert im Minimalprojekt einwandfrei.

    Ich nutze vs2010 unter Windows Xp.

    Wenn ich Deine Punkte durch gehe, dann stellen schaut das bei mir so aus:

    - ansonsten noch genug Speicher: Meinst Du damit der freie Platz auf Festplatte C:? Hier sind 21,5GB frei. Das sollte gut sein, oder?

    - Wie kann ich ein Schaden an der Laufzeit-Runtime feststellen? Und kommt das zum Zug, wenn das Problem sowohl auf meinem XP ist als auch auf dem produktiven Webserver Windows 2008?

    - Wie finde ich heraus, ob in dem Code Com-Interop oder PINvoke verwendet wurde?

    - Wie validiere ich ein JPG? Das Bild lässt sich ohne weiteres im Photoshop öffnen und bearbeiten.

     

    - Wie hast Du heraus gefunden, dass die 4MB Datei 200MB Speicher braucht? Hatte bereits andere Bilder die grösser waren und funktioniert haben.

     

    Verzeih, wenn ich so spät abends so viele Fragen habe. Aber irgendwie muss ich das Problem im Code lösen.

    Vielen lieben Dank
    Gruss Sabrina

    Montag, 20. Dezember 2010 21:40
  • Sabrina,

     > freie Platz auf Festplatte

    die 21GB sind OK, aber eher geht es hier ums RAM, wieviel physikalisch eingebaut, wieviel frei.
    Und wieviel der Prozess deiner App benötigt.
      (alles im Windows TaskManager nachzusehen,  wie auch Angaben zur Auslagerungsdatei/Pagefile)

     > die 4MB Datei 200MB Speicher braucht?

    einerseits sieht man den Sprung um 200MB auch im Taskmanager, andererseits berechenbar:
      Auflösung: 7056x9708, also 68'499'648 Pixels, RGB24 = je 3 Byte pro Pixel = 205498944 Bytes  (~200MB)
    Wobei dies kurzzeitig uU nochmals deutlich mehr sein kann, wegen Umwandlung in interne (GDI+) Formate.

     > ob in dem Code Com-Interop oder PINvoke verwendet wurde?

    wenn du irgendwo Code/COMponenten/APIs nutzt, die nicht in .NET (managed) geschrieben wurden.
    Für APIs, suche deinen ganzen Code nach dem 'Declare' Befehle oder DllImport-Attribute.

     > Wie validiere ich ein JPG? Das Bild lässt sich ohne weiteres im Photoshop öffnen

    wenn das Bild in vielen ganz verschiedenen Apps fehlerfrei zu öffnen ist,
    dann ist dies schon ein recht guter Test.
      (ich habe etwa auch mit Paint.NET geprüft, OK)
    Aber es gäbe offenbar Tools (zT kommerziell), welche 'gründlicher' prüfen
       (ist so keine .NET Frage mehr)

    Wichtig, gleich als nächstes solltest du unbedingt prüfen, dass du allfällig zuvor geladene Bilder wieder freigibst, also in der Art:  bild1.Dispose().
    Achte dabei wie gesagt im TaskManager auf den Speicherbedarf deines Prozesses, dieser sollte nie mehr als auf die 200MB (plus echten Grundbedarf von typ. 20-100MB) steigen!
      (falls grössere Werte, bitte hier mitteilen)


    Ansonst weiteres Vorgehen  (überhaupt genug RAM jetzt mal vorausgesetzt!):
    erstelle eine Kopie/Backup deiner vollen App,
    entferne schrittweise allen 'fremden' Code und Komponenten / Verweise / Declare/DllImport.
    Nach jedem Schritt prüfe mit deinem obigen Code für Bitmap.

    Montag, 20. Dezember 2010 22:12
  • Salü Thomas

    Vielen Dank für Deine Ausführungen.

    Ich konnte den Speicheranstieg auf die rund 200 MB beim Bild Thiersheim nachvollziehen. Das ist ja gigantisch für nur gerade mal eine 4MB Datei. Bei anderen Bildern sehe ich, dass er auf über 600MB ansteigt.

    Bei diesen Speichermengen frage ich mich nun, ob es noch sinnvoll ist, nach irgend welchen Com Komponenten zu suchen, weil diese ja wohl nicht hundert MB frei machen würden.

    .Dispose wird im Code gemacht.

    sourceImage ist vom Typ Bitmap. Der Stream liefert ein Image zurück. Ich habe probiert DimsourceImage as Image weil ich dachte, durch die nicht mehr nötige Konvertierung wäre ich das Speicherproblem los. Aber weit gefehlt, auch wenn sourceImage Image ist und der Stream image ist, brauche ich immer noch 200 MB Ram.

    Kann ich dieses Bild aus dem Stream nicht irgendwie laden, ohne dass ich es entkomprimieren muss?

    Dim imageStream As MemoryStream = New MemoryStream(image)
    Dim sourceImage As Bitmap
    sourceImage = CType(Bitmap.FromStream(imageStream), Bitmap) 'xxx <-- Fehler verursachende Zeile

     

    Der Server hat 4 GB Ram.

    Viele Grüsse
    Sabrina

    Dienstag, 21. Dezember 2010 12:50
  • Sabrina,

    ich sehe eher, dass du uns hier mal genauer sagen musst, wozu du die Bilder technisch brauchst (Weiterverarbeitung/Darstellung usw ?).
    Denn eine Auflösung von den 7056x9708 ist um Faktor 5-10 zu gross, um zum Beispiel auf gängigen Bildschirmen (1:1) voll darzustellen!
    Denn falls du die Bilder gar nie auf dem Bildschirm anzeigst, dann wäre diese WinForms (GDI+) Bitmap-Klasse evtl hier gar fehl am Platz.

    Und was du mit dem MemoryStream erreichen willst ist mir nicht klar (ist in deinem Code nur ein Umweg, löst eigentliches Problem in keiner Weise).

    PS:
    Dass der Server 4GB hat ist OK, aber wichtig (mind für deine riesigen Bilder) wäre dann noch, dass es besser ein 64-Bit Betriebssystem sein sollte, damit auch wirklich die 4GB voll ausgenützt werden können  (ggf gar mit 64-Bit .NET App).
    Dienstag, 21. Dezember 2010 13:05
  • Denn falls du die Bilder gar nie auf dem Bildschirm anzeigst, dann wäre diese WinForms (GDI+) Bitmap-Klasse evtl hier gar fehl am Platz.


    Sabrina, ich sehe gerade du hast 'dieselbe' Frage auch im ASP.NET Forum gestellt?
    http://social.msdn.microsoft.com/Forums/de-DE/aspnetajaxmvcde/thread/f2dbf75f-592c-4525-b5b5-6897e1a9e2dc

    Dann solltest du diese Bitmap-Klasse noch viel intensiver hinterfragen, denn die hat unter IIS meist nichts zu suchen  (GDI+ zT gar unzulässig).
    Dienstag, 21. Dezember 2010 13:37
  • Salü Thomas

    Vielen Dank für Deine Antwort und sehr interessanten Hinweis.

    Ich entnehme Deiner Ausführung, dass die Bitmap Klasse für ein ASP.NET WebProjekt nicht geeignet ist. Was wäre denn eine interessante Klasse um ein Bild welches im SQL Server in einem Feld vom Typ Image habe?

    Das Bild soll vom Anwender hochgeladen werden können, in der Datenbank abgespeichert und dann aus der Datenbank im Browser angezeigt werden können.

    Viele liebe Grüsse
    Sabrina

    Mittwoch, 22. Dezember 2010 07:43
  • Sabrina, wenn es nun um ASP.NET-Vorgänge geht,
    dann wird dabei direkt auf dem Server das Bild doch nie auf einem Bildschirm angezeigt?
       (die Client-Browser Seite ist irrelevant)
    und ich schätze, du willst dabei den Bild-Inhalt doch auch nicht verändern (nur als Bsp einen Text darüber malen)?

    => Dann brauchst du auch gar keine Klasse, die den (ganzen) Bild-Inhalt (Pixels) 'auspacken' muss.
       (und die WinForms- Bitmap Klasse wäre damit ganz hinfällig)


    Generell:
    Bilder (wie auch andere binäre Dateien) sollte man rund um ASP.NET und SQL DB
    bloss als 'Rohdaten' betrachten.
    Und im .NET-Umfeld entspricht dies Byte-Array oder insbesondere Streams (bei grössere Datenmengen)!

    Mir sind die neusten Details in ASP.NET/SQL nicht geläufig,
    aber anhand deiner Beschreibung scheint mir ein Ansatz:

    ASP.NET UPLOAD ... FILESTREAM in SQL Server 2008
    http://www.harborobjects.com/AllenBerezovsky/post/2009/03/04/FILESTREAM-in-SQL-Server-2008.aspx

    http://blogs.microsoft.co.il/blogs/bursteg/archive/2008/05/12/sqlfilestream-managed-api-for-sql-server-2008-filestream.aspx

    Mittwoch, 22. Dezember 2010 08:46
  • Salü Thomas

    Ich denke, Du hast die wahre Antwort auf mein Problem erkannt und gefunden und mich mit Deinen Hinweisen in die richtige Richtung geleitet. Die beiden Links helfen mir gut weiter. Danke Dir vielmals.

    Nachdem ich den bestehenden Code weiter angeschaut habe, sehe ich es auch so wie Du, dass die Bitmap Klasse vermutlich überflüssig ist. Es wird im späteren Verlauf nur noch die Grösse X und Y aus dem Image ausgelesen und danach .dispose. Das Bild kommt tatsächlich über ein Byte Array in die Datenbank hinein.

    Daher denke ich, ich bedanke mich in diesem Trade ganz herzlich für Deine Ausführungen und Hilfestellungen und suche in einem anderen Trade nach der Lösung um auf die benötigten Bilddimensionen X und Y zu kommen wenn ich "nur" ein Byte Array zur Verfügung habe.

    Viele liebe Grüsse
    Sabrina

    Mittwoch, 22. Dezember 2010 09:05
  • Zur Vollständigkeit hier ein Nachtrag aus dem Folgethread:
    http://social.msdn.microsoft.com/Forums/de-DE/dotnetframeworkde/thread/29744f66-d93d-4b4a-b3ec-58a3989d2333

    Ich habe noch etwas tiefer nachgeforscht, warum Bitmap   (GDI+) die ganzen Pixel-Daten auspackt.

    Dabei bin ich auf folgende interessante Tatsache gestossen
    Image.FromStream (validateImageData FALSE)
    http://support.microsoft.com/kb/831419
    http://msdn.microsoft.com/de-de/library/21zw9ah6.aspx

    Es ändert sich zwar nichts am MS-Support Problem, aber
    du könntest mal folgenden Code versuchen, der sollte nicht mehr diese 200-600MB verschlingen (mind bei mir):

    Dim bildFormat As ImageFormat
    Dim bildBreite As Integer
    Dim bildHoehe As Integer
    Dim bildPixels As PixelFormat
    Dim raw As Byte() = File.ReadAllBytes("!!DeinPfad!! THIERSHEIM.jpg")
    Using mms As New MemoryStream(raw, False)
     Using img As Image = Image.FromStream(mms, False, False)
      Dim bmp As Bitmap = CType(img, Bitmap)
      bildFormat = bmp.RawFormat
      bildBreite = bmp.Width
      bildHoehe = bmp.Height
      bildPixels = bmp.PixelFormat
     End Using
    End Using
    
    
    Dienstag, 28. Dezember 2010 07:41