HttpRequest / HttpResponse内存泄漏? CF.NET 3.5 WIN CE 6.0 - c#

我已经尽一切努力使possito摆脱了我认为是Win CE 6.0设备上运行的CF.NET 3.5中的HttpRequest或HttpResponse类导致的内存泄漏。我正在使用它们与IP摄像机通信。

下面是我正在使用的当前代码。代码在线程上的自定义控件中运行,其优先级设置为低于正常,而backgroundworker设置为true。在我的一种表单上有两个控制对象。

我之所以说是当前的,是因为我尝试了以下代码的异步请求和其他排列,而没有减少内存消耗:

    protected void CamRefreshThread()
    {
        while (true)
        {
            if (false != CamEnabled)
            {
                HttpWebRequest  HttpReq = null;

                try
                {
                    lock (LockObject)
                    {
                        // create request
                        HttpReq = (HttpWebRequest)WebRequest.Create("http://" + this.Ipv4Address + "/axis-cgi/jpg/image.cgi");
                        HttpReq.Timeout = 5000;
                        HttpReq.ReadWriteTimeout = 5000;
                        HttpReq.Credentials = new NetworkCredential(this.CamUserName, this.CamPassword);
                    }

                    /* indicate waiting for reponse */
                    ResponseRxed = false;
                    // get response
                    using (HttpWebResponse HttpResp = (HttpWebResponse)HttpReq.GetResponse())
                    {
                        // get response streamImageFromStream
                        using (Stream ImgStream = HttpResp.GetResponseStream())
                        {
                            // get bitmap
                            using (Bitmap ImgFrmStream = new Bitmap(ImgStream))
                            {
                                if (false != CamEnabled)
                                {
                                    /* indicate response has not timed out */
                                    ResponseTimedOut = false;
                                    ResponseFirst = true;
                                    // marshall bitmap
                                    this.Invoke(GetBitmapDelegate, ImgFrmStream);
                                    /* indicate response rxed */
                                    ResponseRxed = true;
                                }
                            }
                        }
                    }
                }
                catch (WebException e)
                {
                    if (false == ResponseTimedOut)
                    {
                        ResponseTimedOut = true;
                        ResponseFirst = false;
                        this.Invoke(RefreshDisplayDelegate);
                    }
                }
                catch (Exception)
                {

                }
                finally
                {
                    if (null != HttpReq)
                    {
                        HttpReq.Abort();
                    }
                }
            }

            Thread.Sleep(1);
        }
    }

我已经使用RPM对它进行了概要分析,并且随着内存的增长,System.Net命名空间和System.Threading命名空间的一堆根对象也是如此,其中包括一堆我没有创建的线程和同步对象。

我已附加了第一个和最后一个堆快照的堆比较图像。

我已经确保在所有允许它的对象上使用“ using”并调用dispose。另外,我确保在完成后中止请求。我在其他示例中已经看到了这一点,应该释放连接资源等。

这是一个奇怪的部分,如果我没有连接摄像机,则仅在抛出超时WebException时才会发生泄漏。连接摄像机后,设备可以运行数天而不会增加内存。另外,RPM中托管字节数和字节总数都在增加,因此我认为这不是未处理的泄漏。最后,我试图尽快从照相机中获取图像。我开始怀疑我是否只是没有给GC时间收集。但是,当发生收集时(我看到收集计数以RPM递增),托管字节数不会减少,而是保持增长。希望我做的事情很愚蠢,这很容易解决。一如既往,任何帮助或建议,我们感激不尽。

附加信息:

如果可能有助于了解,则从照相机线程调用的两个委托如下:

GetBitmapDelegate = new VoidDelegateBitmap(UpdateCamImage);
RefreshDisplayDelegate = new VoidDelegateVoid(RefreshCamImage);

protected void UpdateCamImage(Bitmap Frame)
{
    if (null != BmpOffscreen)
    {
        BmpOffscreen.Dispose();
    }

    BmpOffscreen = (Bitmap)Frame.Clone();
    Refresh();
}

protected void RefreshCamImage()
{
    Refresh();
}

附加信息2:

为了完成此信息,我在下面添加了OnPaint()等。我曾将位图绘制到摄像机的屏幕上:

protected override void OnPaint(PaintEventArgs e)
{
    string DisplayString = null;

    if (false == CamEnabled)
    {
        DisplayString = string.Empty;
    }
    else if (false != ResponseTimedOut)
    {
        DisplayString = "Communication Timeout!";
    }
    else if ((null != BmpOffscreen) && (false != ResponseFirst))
    {
        e.Graphics.DrawImage(BmpOffscreen, 0, 0);
    }
    else
    {
        DisplayString = "Loading...";
    }

    if (null != DisplayString)
    {
        e.Graphics.Clear(this.BackColor);

        using (SolidBrush StringBrush = new SolidBrush(this.ForeColor))
        {
            using (StringFormat Format = new StringFormat())
            {
                Format.LineAlignment = StringAlignment.Center;
                Format.Alignment = StringAlignment.Center;
                e.Graphics.DrawString(DisplayString, this.Font, StringBrush, this.ClientRectangle, Format);
            }
        }
    }
}

protected override void OnPaintBackground(PaintEventArgs e)
{

}

更新:

这是我不明白的。由于HttpRequest只是一个保存信息的对象,并且无法关闭/处理,并且由于抛出WebException超时而HttpResponse仍然为null(无法关闭),因此引用用于尝试该请求的资源是什么?唯一的解释是HttpRequest对象拥有一些引用,该引用在调用Abort时应释放用于发出请求的资源,而我看到的这些资源在RPM中没有恢复。由于我调用Abort(),并且由于HttpRequest对象仅在请求期间处于作用域内,因此我看不到如何无法收集任何引用的资源。

更新2:

好吧,我让它在启用摄像头的情况下运行并允许超时继续,然后我禁用了摄像头,消除了HttpRequest尝试和超时,并让它在一天的剩余时间内运行。归根结底,GC停留在相同的值(根据过去的测试,它应该增长了约6MB),证明这与给GC收集时间无关,至少在我看来。因此,资源仍然处于混乱状态,我需要弄清楚到底是什么使它们扎根。希望我能明白
并给出另一个更新。直到那时...

边注:

是否有人在使用CF.NET 3.5的WIN CE设备上使用HttpRequest / HttpResponse从IP摄像机获取图像?如果是这样,是否有一个测试案例来确定在不确定的时间内相机丢失通讯?那应该是我问的第一件事,因为我还没有找到很多示例来说明如何从嵌入式设备与IP摄像机通信。

更新3:

好吧,我认为我偶然发现了针对我特定问题的修复程序。关于默认连接数和最大空闲时间,我对ServicePointManager静态类成员进行了一些更改:

ServicePointManager.DefaultConnectionLimit = 4;
ServicePointManager.MaxServicePointIdleTime = 1000;

由于我随时最多可以连接4个摄像头,并且由于HttpRequest的超时设置为5000ms,因此我认为我将尝试最大1000ms的空闲时间来查看会发生什么情况。我让两个装置在没有连接相机的情况下通宵运行(每5000毫秒定时)。通常会发生的是我早上来了,设备将坐在那里,并收到一条OOM消息,并且GC内存和物理内存将为我的系统最大化。嗯,这两个设备的存储级别与我昨晚离开时的存储级别相同。因此,我希望这是解决我的问题的方法。基于MSDN文档:

ConnectionLimit属性设置ServicePoint可以与Internet资源建立的最大连接数。创建ServicePoint时,ConnectionLimit属性的值设置为ServicePointManager.DefaultConnectionLimit属性的值。随后对DefaultConnectionLimit的更改对现有ServicePoint实例无效。

MaxIdleTime属性包含以毫秒为单位的时间长度,允许ServicePoint保留与Internet资源的空闲连接,然后再将其回收再用于其他连接。您可以将MaxIdleTime设置为Timeout.Infinite,以指示ServicePoint永不超时。创建ServicePoint时,MaxIdleTime属性的默认值为ServicePointManager.MaxServicePointIdleTime属性的值。对MaxServicePointIdleTime属性的后续更改对现有ServicePoint实例无效。

MaxServicePointIdleTime属性设置创建ServicePoint实例时ServicePointManager分配给MaxIdleTime属性的最大空闲时间。对该值所做的更改将仅影响在更改该值之后初始化的ServicePoint实例。 ServicePoint闲置了MaxIdleTime中指定的时间后,就可以进行垃圾回收。当与ServicePoint关联的连接列表为空时,ServicePoint处于空闲状态。

对我而言,所有这些的关键是明确指出,在服务点处于最大空闲时间后处于空闲状态之后,就可以进行垃圾收集了。我已经看到100到900秒之间的任何时间作为此值的默认值,具体取决于描述所涉及的框架版本。在我认为这是修复程序之前,我将做更多测试。我想从任何玩过这些属性的人那里解决他们的特定问题,以及这是否是我所看到的问题的根本原因是否有意义。

参考方案

只需将您的AllowWriteStreamBuffering对象的HttpWebRequest属性设置为false:

HttpReq.AllowWriteStreamBuffering = false;
HttpReq.AllowAutoRedirect = false;

Visual Studio,ASP.Net(.Net Framework),并在项目中包含NuGet安装的软件包 - javascript

我在Visual Studio 2017中有一个主要由JavaScript组成的ASP.Net(.Net Framework)MVC Web应用程序。我已经使用NuGet安装了一个软件包(特别是marker-animate-unobtrusive软件包。)文档继续说我应该在我的HTML页面中包含JavaScript,但是在仔细检查了NuGet的内容后,我不确…

在ASP.NET MVC中创建数据库回调的最有效方法 - c#

我有一个ASP.NET MVC网页,该网页基本上通过日期过滤器显示MS SQL数据库中表的行。当新行插入数据库表时,我想用新行列表更新网页视图。实现此目标的最有效方法是什么?基本上,我想从我的JavaScript创建一个到数据库服务器的回调,以用新结果更新UI。假设数据库表中的行数很大。(〜1百万)谢谢,cas 参考方案 如果数据库更新非常频繁,则可以按特定…

ddl在服务器中未更新-asp.net - javascript

我在ASP.NET c#上工作。我有一个DropDownList。 (runat =“ server”)在$ {document).ready上,我更新了它的值:$(document).ready(function () { document.getElementById("ddl").value = "abc"; ……

从.NET Core 2.1降级到.NET 4.7.1时,如何使用IApplicationBuilder和IServiceCollection? - c#

我不得不将我的项目从.NET Core 2.1更改为.NET 4.7.1,并且修复了几乎所有错误,但以下错误仍然困扰着我 “ IApplicationBuilder”不包含“ UseHsts”的定义,也找不到找不到接受类型为“ IApplicationBuilder”的第一个参数的扩展方法“ UseHsts”(是否缺少using指令或程序集引用?) “ IA…

如何使用ASP.NET ViewState使用JavaScript - c#

我的页面中有UL,它为空。我开始使用JavaScript使用LI填充它。在回发阶段如何在asp.net中使用此新添加的动态数据?那是因为我的提交按钮是asp.net控件。我不想使用JS POST。谢谢 参考方案 我过去通过在隐藏字段中填充要发布的动态数据来完成此类操作,您可以-在回传之前触发JavaScript事件,该事件将数据从UL解析到隐藏字段中要么更新…