2014-10-01 66 views
-1

在我的程序即時捕獲destop窗口的屏幕截圖,每個第二使用定時器: 異常消息爲:爲什麼我要離開內存異常,我應該如何避免它?

System.OutOfMemoryException was unhandled 
    HResult=-2147024882 
    Message=Out of memory. 
    Source=System.Drawing 
    StackTrace: 
     at System.Drawing.Image.Save(String filename, ImageCodecInfo encoder, EncoderParameters encoderParams) 
     at System.Drawing.Image.Save(String filename, ImageFormat format) 
     at CapturedDesktop.Form1.screenshots(String filename) in d:\C-Sharp\CapturedDesktop\CapturedDesktop\CapturedDesktop\Form1.cs:line 53 
     at CapturedDesktop.Form1.CaptureScreenshot() in d:\C-Sharp\CapturedDesktop\CapturedDesktop\CapturedDesktop\Form1.cs:line 31 
     at CapturedDesktop.Form1.timer1_Tick(Object sender, EventArgs e) in d:\C-Sharp\CapturedDesktop\CapturedDesktop\CapturedDesktop\Form1.cs:line 63 
     at System.Windows.Forms.Timer.OnTick(EventArgs e) 
     at System.Windows.Forms.Timer.TimerNativeWindow.WndProc(Message& m) 
     at System.Windows.Forms.NativeWindow.DebuggableCallback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam) 
     at System.Windows.Forms.UnsafeNativeMethods.DispatchMessageW(MSG& msg) 
     at System.Windows.Forms.Application.ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(IntPtr dwComponentID, Int32 reason, Int32 pvLoopData) 
     at System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner(Int32 reason, ApplicationContext context) 
     at System.Windows.Forms.Application.ThreadContext.RunMessageLoop(Int32 reason, ApplicationContext context) 
     at System.Windows.Forms.Application.Run(Form mainForm) 
     at CapturedDesktop.Program.Main() in d:\C-Sharp\CapturedDesktop\CapturedDesktop\CapturedDesktop\Program.cs:line 19 
     at System.AppDomain._nExecuteAssembly(RuntimeAssembly assembly, String[] args) 
     at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args) 
     at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly() 
     at System.Threading.ThreadHelper.ThreadStart_Context(Object state) 
     at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx) 
     at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx) 
     at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state) 
     at System.Threading.ThreadHelper.ThreadStart() 
    InnerException: 

唯一的例外是就行:

bmpScreenshot.Save(filename, ImageFormat.Gif); 

這是savig罰款到硬盤的圖像,直到文件數000110這意味着該程序工作正常110秒,然後出現異常。

也許我應該在某處放置bmp變量?

using System; 
using System.Collections.Generic; 
using System.ComponentModel; 
using System.Data; 
using System.Drawing; 
using System.Linq; 
using System.Text; 
using System.Threading.Tasks; 
using System.Windows.Forms; 
using System.Runtime.InteropServices; 
using System.Drawing.Imaging; 
using System.IO; 
using unfreez_wrapper; 

namespace CapturedDesktop 
{ 
    public partial class Form1 : Form 
    { 
     int screens; 
     string gifsdirectory; 
     UnFreezWrapper unfreez; 

     public Form1() 
     { 
      InitializeComponent(); 

      unfreez = new UnFreezWrapper(); 
      timer1.Enabled = false; 
      screens = 0; 
      gifsdirectory = @"C:\Temp\CapturedDesktop\"; 
     } 


     private void CaptureScreenshot() 
     { 
      screens++; 
      screenshots(gifsdirectory + screens.ToString("D6") + ".gif"); 
     } 

     public static void screenshots(string filename) 
     { 
      //Create a new bitmap. 
      var bmpScreenshot = new Bitmap(Screen.PrimaryScreen.Bounds.Width, 
              Screen.PrimaryScreen.Bounds.Height, 
              PixelFormat.Format32bppArgb); 

      // Create a graphics object from the bitmap. 
      var gfxScreenshot = Graphics.FromImage(bmpScreenshot); 

      // Take the screenshot from the upper left corner to the right bottom corner. 
      gfxScreenshot.CopyFromScreen(Screen.PrimaryScreen.Bounds.X, 
             Screen.PrimaryScreen.Bounds.Y, 
             0, 
             0, 
             Screen.PrimaryScreen.Bounds.Size, 
             CopyPixelOperation.SourceCopy); 

      // Save the screenshot to the specified path that the user has chosen. 
      bmpScreenshot.Save(filename, ImageFormat.Gif); 
     } 

     private void Form1_Load(object sender, EventArgs e) 
     { 

     } 

     private void timer1_Tick(object sender, EventArgs e) 
     { 
      CaptureScreenshot(); 
     } 

     private void AnimatedGifButton_Click(object sender, EventArgs e) 
     { 
      List<string> myGifList = new List<string>(); 
      FileInfo[] fi; 
      DirectoryInfo dir1 = new DirectoryInfo(gifsdirectory); 
      fi = dir1.GetFiles("*.gif"); 
      for (int i = 0; i < fi.Length; i++) 
      { 
       myGifList.Add(fi[i].FullName); 
      } 
      unfreez.MakeGIF(myGifList, gifsdirectory + "agif", 100, true); 
     } 
    } 
} 
+0

'這意味着程序工作正常110秒,然後出現異常。「 - 這是否意味着大約需要110秒來保存文件? – TheGeekZn 2014-10-01 06:34:36

+0

SemiDemented什麼文件?這意味着它需要110秒來保存110個文件。 000110是第一個文件的最後一個文件是000000.gif定時器間隔爲1000ms。我的意思是花了110秒鐘纔將所有文件保存到000110,然後是文件000110.gif,這是110秒,而不是創建000111.gif它顯示異常。 – 2014-10-01 06:36:37

+0

是的,你當然應該處理你的位圖。內存不足的例外是一個死的贈品。每個問題有一個問題! Stackoverflow不是一個論壇。閱讀[問]。 – dandan78 2014-10-01 06:36:55

回答

3

保存圖像後,您需要Dispose它。否則,你將所有責任推到GC。 GC有時可以拯救你,有時不會。

鑑於圖像大小等於屏幕大小,這意味着圖像佔用的內存也將很大。你應該儘快處理它,只要你不需要它。

public static void screenshots(string filename) 
{ 
    //Create a new bitmap. 
    using(var bmpScreenshot = new Bitmap(Screen.PrimaryScreen.Bounds.Width, 
            Screen.PrimaryScreen.Bounds.Height, 
            PixelFormat.Format32bppArgb)) 
    { 
     // Create a graphics object from the bitmap. 
     using(var gfxScreenshot = Graphics.FromImage(bmpScreenshot)) 
     { 

      // Take the screenshot from the upper left corner to the right bottom corner. 
      gfxScreenshot.CopyFromScreen(Screen.PrimaryScreen.Bounds.X, 
            Screen.PrimaryScreen.Bounds.Y, 
            0, 
            0, 
            Screen.PrimaryScreen.Bounds.Size, 
            CopyPixelOperation.SourceCopy); 
     } 
     // Save the screenshot to the specified path that the user has chosen. 
     bmpScreenshot.Save(filename, ImageFormat.Gif); 
    } 
} 

不想using statementsDispose一次性資源。

+0

還有['Graphics'](http://msdn.microsoft.com/en-us/library/system.drawing.graphics.dispose%28v=vs.110%29.aspx),雖然那不重要。 – dbc 2014-10-01 06:39:01

+0

@dbc謝謝,我還補充說。這不是那麼重要。這很重要。只能創建[最多65,536個gdi對象](http://msdn.microsoft.com/en-us/library/windows/desktop/ms724291%28v=vs.85%29.aspx)。您應該釋放先前的分配以創建更多。 – 2014-10-01 06:44:53

+0

@Sriram Sakthivel調用dispose是一種很好的做法,但不是強制性的,正如你所建議的,GC總是會出現在圖片中,並且它做了相當不錯的清理工作,在這種情況下會出現其他各種因素,比如上面的對象是本地的,所以它快速收集。在這種情況下,創建對象的頻率,像3GB(32位)的內存設置,甚至像GC.Collect,GC.WaitForPendingFinalizers這樣的顯式GC調用可以節省一天的時間,爲GC提供足夠的時間來降低整體內存壓力 – 2014-10-01 07:28:31

相關問題