私は現在のスクリーンショットを表示し、それをaviファイルに連続的に書き込むサンプルアプリケーションを作成しています。私はSharpAviをaviの書き込みに使用しています。私の問題は、私は、この例外がスロー取得しています:C#メモリ不足の例外を修正するにはどうすればよいですか?
「型 『System.OutOfMemoryExceptionに』の未処理の例外がSystem.Drawing.dll
で発生しました追加情報:メモリ不足。」
私が呼び出すLockBits()メソッドと関係があり、アプリケーションを実行してから約30秒後に例外が発生すると思います。ここで
スクリーンショットを取る私のコードです:ここでは
public class Recording
{
//...
private void TakeScreenshot(byte[] buffer)
{
using (var bitmap = new System.Drawing.Bitmap(m_screenWidth, m_screenHeight))
{
using (var g = System.Drawing.Graphics.FromImage(bitmap))
{
g.CopyFromScreen(m_screenLeft, m_screenTop, 0, 0, new System.Drawing.Size(m_screenWidth, m_screenHeight), System.Drawing.CopyPixelOperation.SourceCopy);
// Draw cursor.
User32.CURSORINFO pci;
pci.cbSize = Marshal.SizeOf(typeof(User32.CURSORINFO));
if (User32.GetCursorInfo(out pci))
{
if (pci.flags == User32.CURSOR_SHOWING)
{
User32.DrawIcon(g.GetHdc(), pci.ptScrenPos.x - m_screenLeft, pci.ptScrenPos.y - m_screenTop, pci.hCursor);
g.ReleaseHdc();
}
}
if (OnScreenCapture != null)
{
CaptureEventArgs args = new CaptureEventArgs(bitmap);
OnScreenCapture(this, args);
}
var bits = bitmap.LockBits(new Rectangle(// code breaks here
0,
0,
m_screenWidth,
m_screenHeight),
ImageLockMode.ReadOnly,
System.Drawing.Imaging.PixelFormat.Format32bppRgb);
Marshal.Copy(bits.Scan0, buffer, 0, buffer.Length);
bitmap.UnlockBits(bits);
}
}
}
}
public class CaptureEventArgs : EventArgs
{
public System.Windows.Media.Imaging.BitmapSource BitmapSource
{
get;
private set;
}
public CaptureEventArgs(Bitmap bitmap)
{
BitmapSource = System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap(
bitmap.GetHbitmap(),
IntPtr.Zero,
Int32Rect.Empty,
System.Windows.Media.Imaging.BitmapSizeOptions.FromEmptyOptions());
BitmapSource.Freeze();
}
}
}
は私MainWindow.xaml.csです:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
m_recordTimer = new DispatcherTimer();
m_recordTimer.Interval = TimeSpan.FromSeconds(1);
m_recordTimer.Tick += recordTimer_Tick;
m_stopwatch = new Stopwatch();
DataContext = this;
}
private void recordTimer_Tick(object sender, EventArgs e)
{
var elapsed = m_stopwatch.Elapsed;
Elapsed = string.Format("{00:00}:{1:00}", Math.Floor(elapsed.TotalMinutes), elapsed.Seconds);
}
private void btnStart_Click(object sender, RoutedEventArgs e)
{
StartRecording();
}
private void btnStop_Click(object sender, RoutedEventArgs e)
{
StopRecording();
}
private void StartRecording()
{
if(IsRecording)
{
return;
}
IsRecording = true;
Elapsed = "00:00";
IsLastScreenshot = false;
m_stopwatch.Reset();
m_recordTimer.Start();
m_lastFileName = System.IO.Path.Combine("", DateTime.Now.ToString("yyyy-MM-dd-HH-mm-ss") + ".avi");
m_recorder = new Recording(m_lastFileName, KnownFourCCs.Codecs.MotionJpeg, 70, this);
m_stopwatch.Start();
m_recorder.OnScreenCapture += m_recorder_OnScreenCapture;
}
void m_recorder_OnScreenCapture(object sender, CaptureEventArgs e)
{
imgLive.Dispatcher.BeginInvoke((Action)delegate
{
imgLive.Source = e.BitmapSource;
});
}
private void StopRecording()
{
if (!IsRecording)
{
return;
}
m_recorder.Dispose();
m_recorder = null;
m_recordTimer.Stop();
m_stopwatch.Stop();
IsRecording = false;
IsLastScreenshot = true;
}
public bool IsRecording { get; private set; }
public string Elapsed { get; private set; }
public bool IsLastScreenshot { get; private set; }
#region fields
private DispatcherTimer m_recordTimer;
private readonly Stopwatch m_stopwatch;
private Recording m_recorder;
private string m_lastFileName;
#endregion
internal void SetImage(System.Drawing.Bitmap bitmap)
{
imgLive.Dispatcher.BeginInvoke((Action)delegate
{
imgLive.Source = System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap(
bitmap.GetHbitmap(),
IntPtr.Zero,
Int32Rect.Empty,
System.Windows.Media.Imaging.BitmapSizeOptions.FromEmptyOptions());
});
}
}
は、私はより多くのコードを投稿する必要がある場合は、私を知ってみましょう。私は必要なものだけを見せようとしています。また、私は経験豊富ではないと言及する必要があります。私はスレッドとメモリ管理についてちょっと知っています。そして改善のための提案をします。
スタックトレースを取得しましたか? – n8wrl
私の最初の考えは、あなたが以前のスクリーンショットをaviに書き込んだ後で解放していないということです。それを見てください。 – ChrisF
一見したところでは、「使用する」ことでビットマップを破棄していることを示しています。ロックされたビットを解放すると、ロックされたビットが解放されます。私はデバッガに入り、さまざまなパラメータの数値を調べることをお勧めします。場合によっては何かがうまくいかず、0(ゼロ)をグラフィックスシステムに渡して高さや幅を渡すとOOM例外が発生します。 –