发送屏幕截图占用太多内存

本文关键字:太多 内存 屏幕截图 | 更新日期: 2023-09-27 17:59:43

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

是我的代码不好,还是nancy不适合处理许多大的响应,或者是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)
                };
            }
        };
    }
}

发送屏幕截图占用太多内存

尽可能地将变量保持在最局部的范围内,并尽可能地处理掉。

问题的一部分可能是您正在重复地新建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)
    };
}