发送截图占用太多内存

时间:2014-04-23 00:34:27

标签: c# memory screenshot nancy

我正在尝试通过网络制作一个小应用程序来提供整个屏幕的截图。我希望它能够通过LAN每1-2秒服务一次。我认为它不会成为一个大问题,所以我选择了C#和nancy www self host(作为最简单的选项)。现在,速度可以满足我的需求,但它似乎占用了太多的内存,而且随着时间的推移而增长。它似乎决定占用大约3.5 GB的内存,从那时起不再增长,但这是不可接受的数量 - 即使分辨率很高(我的是2560x1440)。

我的代码是坏的,还是不适合处理很多大的响应,或者C#捕获屏幕的方法很难优化,我应该尝试pinvoke方法?或者它可能只是一种可怕的方式,我应该尝试更高级的东西,比如使用VNC库?

目前我的代码如下:

public class HomeModule : NancyModule
{
    private Bitmap bitmapScreenCapture;
    private Graphics graphics;
    private Object lockMe = new object();
    private MemoryStream memoryStream = new MemoryStream();

    public HomeModule()
    {
        Get["image"] = parameters =>
        {
            lock (lockMe)
            {
                GC.Collect();

                if (bitmapScreenCapture == null || bitmapScreenCapture.Width != Screen.PrimaryScreen.Bounds.Width || bitmapScreenCapture.Height != Screen.PrimaryScreen.Bounds.Height)
                {
                    if (bitmapScreenCapture != null)
                    {
                        bitmapScreenCapture.Dispose();
                    }
                    bitmapScreenCapture = new Bitmap(Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height);
                    graphics = Graphics.FromImage(bitmapScreenCapture);
                }

                graphics.CopyFromScreen(Screen.PrimaryScreen.Bounds.X,
                    Screen.PrimaryScreen.Bounds.Y,
                    0, 0,
                    bitmapScreenCapture.Size,
                    CopyPixelOperation.SourceCopy);

                bitmapScreenCapture.Save(memoryStream, ImageFormat.Png);
                memoryStream.Position = 0;

                return new Response()
                {
                    Contents = stream => memoryStream.CopyTo(stream)
                };
            }
        };
    }
}

1 个答案:

答案 0 :(得分:1)

尽可能将变量保留在最本地范围内,并尽可能处置。

您的部分问题可能是您重复使用Graphics实例,但从不丢弃旧参考。 GC最终会收集它,但您可以将代码放在using块中,让它知道您完成了它。

我尚未对此进行测试,但在此我已将您的实例设为本地,并处理了GraphicsBitmap个实例。我没有处置MemoryStream因为我不确定如果你这样做会成功返回值,但你可以使用它。

var screen = Screen.PrimaryScreen;

using (var bitmap = new Bitmap(screen.Bounds.Width, screen.Bounds.Height))
{
    using (var g = Graphics.FromImage(bitmap))
    {
        g.CopyFromScreen(screen.Bounds.Left, screen.Bounds.Top, 0, 0, screen.Bounds.Size);
    }

    var imageStream = new MemoryStream();
    bitmap.Save(imageStream, ImageFormat.Png);
    imageStream.Position = 0;

    return new Response()
    {
        Contents = stream => memoryStream.CopyTo(stream)
    };
}