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

C# HttpRequest/HttpResponse内存泄漏?CF.NET 3.5 WIN CE 6.0,c#,windows-ce,httprequest,httpresponse,compact-framework,C#,Windows Ce,Httprequest,Httpresponse,Compact Framework,我已经尽了一切可能,在Win CE 6.0设备上运行CF.NET 3.5中的HttpRequest或HttpResponse类,以消除我认为的内存泄漏。我正在用它们与IP摄像机进行通信 下面是我正在使用的当前代码。代码在线程上的自定义控件中运行,其优先级设置为低于正常值,backgroundworker设置为true。我的一个窗体上有两个这样的控件对象 我之所以说当前,是因为我尝试了异步请求和以下代码的其他排列,但没有减少内存消耗: protected void CamRefreshTh

我已经尽了一切可能,在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收集时间无关。所以这些资源仍然处于不确定状态,我需要弄清楚到底是什么让它们生根发芽。希望我能明白 请退出并提供另一个更新。在那之前

旁注:

是否有人使用过HttpRequest/HttpResponse在使用CF.NET 3.5的WIN CE设备上从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永远不应超时。MaxIdleTime属性的默认值是创建ServicePoint时ServicePointManager.MaxServicePointIdleTime属性的值。对MaxServicePointIdleTime属性的后续更改对现有ServicePoint实例没有影响

MaxServicePointIdleTime属性设置ServicePointManager在创建ServicePoint实例时分配给MaxIdleTime属性的最大空闲时间。对此值所做的更改将只影响到需要重新配置的ServicePoint实例
HttpReq.AllowWriteStreamBuffering = false;
HttpReq.AllowAutoRedirect = false;