2013-04-17 16 views
6

Ich kann einfach nicht für das Leben von mir herauszufinden, warum ich hier eine aus dem Speicher Ausnahme bekomme, auch nach viel Forschung auf verschiedenen Websites und Foren. Kann jemand die Wurzel allen Übels in diesem Code beleuchten? Die Ausnahme wird durch den Aufruf der Graphics.DrawImage() Methode geworfen, Linie 79.Graphics.DrawImage: Nicht genügend Speicher Ausnahme

[HttpPost] 
    [ValidateAntiForgeryToken] 
    public ActionResult EditImage(FileModel model) 
    { 
     var fileData = new MySite.Models.File(model.FileID, model.ClientID, ConfigurationManager.ConnectionStrings["MySite"].ConnectionString).Data; 
     Image image = null; 

     using (var memStream = new MemoryStream()) 
     { 
      memStream.Write(fileData, 0, fileData.Length); 
      image = Image.FromStream(memStream); 
     } 

     using (var graphics = Graphics.FromImage(image)) 
     { 
      graphics.DrawImage(image, model.x1, model.y1, (model.x2 - model.x1), (model.y2 - model.y1)); 
      graphics.Save(); 
     } 

     using (var memStream = new MemoryStream()) 
     { 
      image.Save(memStream, System.Drawing.Imaging.ImageFormat.Jpeg); 
      return File(memStream.ToArray(), "image/jpeg"); 
     } 
    } 

Stapelüberwachung:

[OutOfMemoryException: Out of memory.] 
System.Drawing.Graphics.CheckErrorStatus(Int32 status) +1143476 
System.Drawing.Graphics.DrawImage(Image image, Int32 x, Int32 y, Int32 width, Int32 height) +141 
ProPilot.Controllers.DocumentsController.EditImage(FileModel model) in C:\DEV\Web\Controllers\DocumentsController.cs:79 
lambda_method(Closure , ControllerBase , Object[]) +104 
System.Web.Mvc.ActionMethodDispatcher.Execute(ControllerBase controller, Object[] parameters) +14 
System.Web.Mvc.ReflectedActionDescriptor.Execute(ControllerContext controllerContext, IDictionary`2 parameters) +211 
System.Web.Mvc.ControllerActionInvoker.InvokeActionMethod(ControllerContext controllerContext, ActionDescriptor actionDescriptor, IDictionary`2 parameters) +27 
System.Web.Mvc.Async.<>c__DisplayClass42.<BeginInvokeSynchronousActionMethod>b__41() +28 
System.Web.Mvc.Async.<>c__DisplayClass8`1.<BeginSynchronous>b__7(IAsyncResult _) +10 
System.Web.Mvc.Async.WrappedAsyncResult`1.End() +57 
System.Web.Mvc.Async.AsyncControllerActionInvoker.EndInvokeActionMethod(IAsyncResult asyncResult) +48 
System.Web.Mvc.Async.<>c__DisplayClass39.<BeginInvokeActionMethodWithFilters>b__33() +57 
System.Web.Mvc.Async.<>c__DisplayClass4f.<InvokeActionMethodFilterAsynchronously>b__49() +223 
System.Web.Mvc.Async.<>c__DisplayClass37.<BeginInvokeActionMethodWithFilters>b__36(IAsyncResult asyncResult) +10 
System.Web.Mvc.Async.WrappedAsyncResult`1.End() +57 
System.Web.Mvc.Async.AsyncControllerActionInvoker.EndInvokeActionMethodWithFilters(IAsyncResult asyncResult) +48 
System.Web.Mvc.Async.<>c__DisplayClass2a.<BeginInvokeAction>b__20() +24 
System.Web.Mvc.Async.<>c__DisplayClass25.<BeginInvokeAction>b__22(IAsyncResult asyncResult) +102 
System.Web.Mvc.Async.WrappedAsyncResult`1.End() +57 
System.Web.Mvc.Async.AsyncControllerActionInvoker.EndInvokeAction(IAsyncResult asyncResult) +43 
System.Web.Mvc.<>c__DisplayClass1d.<BeginExecuteCore>b__18(IAsyncResult asyncResult) +14 
System.Web.Mvc.Async.<>c__DisplayClass4.<MakeVoidDelegate>b__3(IAsyncResult ar) +23 
System.Web.Mvc.Async.WrappedAsyncResult`1.End() +62 
System.Web.Mvc.Controller.EndExecuteCore(IAsyncResult asyncResult) +57 
System.Web.Mvc.Async.<>c__DisplayClass4.<MakeVoidDelegate>b__3(IAsyncResult ar) +23 
System.Web.Mvc.Async.WrappedAsyncResult`1.End() +62 
System.Web.Mvc.Controller.EndExecute(IAsyncResult asyncResult) +47 
System.Web.Mvc.Controller.System.Web.Mvc.Async.IAsyncController.EndExecute(IAsyncResult asyncResult) +10 
System.Web.Mvc.<>c__DisplayClass8.<BeginProcessRequest>b__3(IAsyncResult asyncResult) +25 
System.Web.Mvc.Async.<>c__DisplayClass4.<MakeVoidDelegate>b__3(IAsyncResult ar) +23 
System.Web.Mvc.Async.WrappedAsyncResult`1.End() +62 
System.Web.Mvc.MvcHandler.EndProcessRequest(IAsyncResult asyncResult) +47 
System.Web.Mvc.MvcHandler.System.Web.IHttpAsyncHandler.EndProcessRequest(IAsyncResult result) +9 
System.Web.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() +9629296 
System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) +155 
+3

auf welcher Linie .. – Sayse

+2

Können wir vielleicht die Stacktrace bekommen? – uriDium

+0

@uriDium Ah, ja natürlich. Entschuldige, dass du es nicht sofort aufgenommen hast! – Maritim

Antwort

9

@Sayse traf den Nagel auf den Kopf mit seinem Kommentar oben.

Wenn Image.FromStream mit:

Sie müssen den Strom für die gesamte Lebensdauer des Bildes offen halten.

Quelle: http://msdn.microsoft.com/en-AU/library/93z9ee4x.aspx

using (var memStream = new MemoryStream()) 
{ 
    memStream.Write(fileData, 0, fileData.Length); 
    using(Image image = Image.FromStream(memStream)) 
    { 
     using (var graphics = Graphics.FromImage(image)) 
     { 
      graphics.DrawImage(image, model.x1, model.y1, (model.x2 - model.x1), (model.y2 - model.y1)); 
      graphics.Save(); 
     } 

     using (var outStream = new MemoryStream()) 
     { 
      image.Save(outStream, System.Drawing.Imaging.ImageFormat.Jpeg); 
      return File(outStream.ToArray(), "image/jpeg"); 
     } 
    } 
} 
+0

Würden Sie bitte mehr erklären? –

+2

@minhcat_vo Das Image basiert darauf, dass der Speicherstrom während seiner gesamten Lebensdauer verfügbar ist. Wenn der Speicherstream in einem * using * ist und das Bild außerhalb des Geltungsbereichs von * using * verwendet wird, wird der Speicherstrom bereits entsorgt. Daher kann das Bild nicht darauf zugreifen und Sie erhalten Ausnahmen wie oben. – Lummo

+0

Was ein STUPID Design ist das? Wenn die Bilddatei in den Speicher gelesen und in einem Image-Objekt gespeichert wurde, für welchen Datenstrom ist der Datenstrom bis zum Ende der Lebensdauer erforderlich? – Elmue

1

Wenn Sie mit dem Bitmap oder Image Klasse arbeiten Sie mehrere Probleme.

Wenn Sie ein Bild mit Image.FromFile() laden, schließt das Framework das Dateihandle nach dem Laden des Bildes nicht. Die Datei bleibt geöffnet, bis der Garbage Collector das Bild erneut speichert. Dies ist ein schwerwiegendes Fehldesign in GDI +. Es ist nicht notwendig, eine Datei offen zu halten, nachdem das Bild bereits in den Speicher eingelesen wurde.

Also habe ich versucht, dieses Problem zu umgehen, indem Sie stattdessen Image.FromStream() verwenden. Aber das ist keine Lösung, denn wenn der Stream geschlossen wurde, wird eine DrawImage() Operation für dieses Image mit "Out of memory" fehlschlagen.

Also, wenn Sie zum Beispiel eine Bitmap aus einer Datei lesen wollen, und Sie wollen sicherstellen, dass die Datei-Handle geschlossen ist, müssen Sie eine hässliche Abhilfe wie folgt verwenden:

Bitmap ReadBitmapFromFile(String s_Path) 
{ 
    using (FileStream i_Stream = new FileStream(s_Path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) 
    { 
     using (Bitmap i_Bmp = new Bitmap(i_Stream)) 
     { 
      return new Bitmap(i_Bmp); 
     } 
    } 
} 

By the way: Image.Clone() erzeugt ein ähnliches Problem.

Statt

Bitmap i_Clone = (Bitmap)i_Bmp.Clone() 

ich benutzen musste:

Bitmap i_Clone = new Bitmap(i_Bmp); 
+0

Re "Es ist nicht notwendig, eine Datei offen zu lassen, nachdem das Bild bereits in den Speicher eingelesen wurde." IMHO, das sind Spekulationen über das interne Design von GDI + - Offensichtlich gibt es einige (interne) Notwendigkeit, die Quelle verfügbar zu halten - Bedauerlicherweise erklären die Dokumente nicht, WARUM das ist - aber dann tut es nie. – ToolmakerSteve

+0

Gut. Ich weiß nicht warum. Du weißt es auch nicht. Aber Tatsache ist, dass die Ausführung des obigen Codes das Bild im Speicher hat und die Datei geschlossen wird. Das bestätigt meinen Satz: Es ist nicht notwendig, eine Datei offen zu halten, nachdem das Bild bereits in den Speicher eingelesen wurde. – Elmue

Verwandte Themen