2013-04-17 34 views
6

Tôi không thể cho cuộc sống của tôi tìm ra lý do tại sao tôi nhận được một bộ nhớ ngoại lệ ở đây, thậm chí sau nhiều nghiên cứu trên các trang web và diễn đàn khác nhau. Có ai có thể làm sáng tỏ nguồn gốc của tất cả điều ác trong đoạn mã này không? Trường hợp ngoại lệ được ném bởi các cuộc gọi đến phương pháp Graphics.DrawImage(), dòng 79.Graphics.DrawImage: Ngoại trừ bộ nhớ

[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"); 
     } 
    } 

Stack trace:

[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

vào những gì dòng .. – Sayse

+2

Chúng ta có thể có thể có được stacktrace? – uriDium

+0

@uriDium Ah, tất nhiên rồi. Xin lỗi vì không bao gồm nó ngay lập tức! – Maritim

Trả lời

9

@Sayse nhấn đinh trên đầu với bình luận của ông trên.

Khi sử dụng Image.FromStream:

Bạn phải giữ cho dòng mở cho các đời của các hình ảnh.

Nguồn: 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

Bạn vui lòng giải thích thêm? –

+2

@minhcat_vo Hình ảnh dựa trên luồng bộ nhớ khả dụng trong suốt cuộc đời của nó. Nếu luồng bộ nhớ trong * sử dụng * và hình ảnh được sử dụng ngoài phạm vi của điều này * sử dụng * luồng bộ nhớ sẽ được xử lý. Do đó hình ảnh không thể truy cập nó và bạn nhận được các ngoại lệ như trên. – Lummo

+0

Thiết kế STUPID là gì? Nếu tệp hình ảnh đã được đọc vào bộ nhớ và được lưu trữ trong đối tượng Hình ảnh thì luồng cần thiết cho đến cuối đời là gì? – Elmue

1

Nếu bạn làm việc với các lớp Bitmap hoặc Image bạn sẽ tìm thấy một số vấn đề.

Nếu bạn tải hình ảnh có Image.FromFile(), khung công tác sẽ không đóng bộ xử lý tệp sau khi tải hình ảnh. Tệp vẫn mở cho đến khi bộ thu gom rác thu hồi hình ảnh. Đây là một misdesign nghiêm trọng trong GDI +. Không cần phải giữ một tập tin mở sau khi hình ảnh đã được đọc vào bộ nhớ.

Vì vậy, tôi đã cố gắng giải quyết vấn đề này bằng cách sử dụng Image.FromStream() để thay thế. Nhưng đây không phải là giải pháp vì khi luồng đã bị đóng hoạt động DrawImage() trên hình ảnh đó sẽ không thành công với "Hết bộ nhớ".

Vì vậy, nếu bạn muốn đọc ví dụ như một Bitmap từ một tập tin và bạn muốn đảm bảo rằng các tập tin xử lý bị đóng, bạn phải sử dụng một workaround xấu xí như thế này:

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); 
     } 
    } 
} 

Bằng cách này: Image.Clone() tạo ra một vấn đề tương tự.

Thay vì

Bitmap i_Clone = (Bitmap)i_Bmp.Clone() 

tôi đã phải sử dụng:

Bitmap i_Clone = new Bitmap(i_Bmp); 
+0

Re "Không cần phải giữ một tập tin mở sau khi hình ảnh đã được đọc vào bộ nhớ." IMHO, Đó là suy đoán về thiết kế nội bộ của GDI + - Rõ ràng, có một số (nội bộ) cần phải giữ nguồn sẵn có - Đáng tiếc, các tài liệu không giải thích TẠI SAO đó - nhưng sau đó các tài liệu không bao giờ làm. – ToolmakerSteve

+0

Vâng. Tôi không biết tại sao. Bạn cũng không biết. Nhưng thực tế là thực thi mã trên của tôi, bạn sẽ có hình ảnh trong bộ nhớ và tập tin sẽ được đóng lại. Điều này xác nhận câu của tôi: Không cần phải mở tệp sau khi hình ảnh đã được đọc vào bộ nhớ. – Elmue

Các vấn đề liên quan