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

问题描述 投票:9回答:2

我已经尝试了在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命名空间的root对象也是如此,其中包括一堆我没有创建的线程和同步对象。

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

我确保使用“使用”并在允许它的所有对象上调用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()等。我曾经将Bitmap绘制到相机的屏幕上:

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仍然为空(无法关闭),引用用于尝试请求的资源是什么?唯一的解释是HttpRequest对象持有一些引用,当调用Abort时,应该释放用于发出请求的资源,我看到的那些资源没有在RPM中恢复。由于我调用Abort()并且因为HttpRequest对象仅在请求期间在作用域中,所以我看不到如何收集引用的任何资源。

UPDATE2:

好吧,我让它在启用摄像头的情况下运行并允许超时继续,然后我禁用了摄像头,消除了HttpRequest尝试和超时,让它在一天的剩余时间运行。在一天结束时,GC停留在相同的值(基于过去的测试,它应该增长大约6MB),证明这与给GC收集时间无关,至少我认为。所以资源仍处于不确定状态,我需要弄清楚究竟是什么让它们扎根。希望我能解决这个问题并给出另一个更新。直到那时...

边注:

有没有人用过HttpRequest / HttpResponse从使用CF.NET 3.5的WIN CE设备上的IP摄像头获取图像?如果是这样,是否有一个测试案例可以无限期地从相机中丢失通讯?这应该是我问的第一件事,因为我没有找到很多例子来展示如何从嵌入式设备与IP摄像机进行通信。

UPDATE3:

好吧,我想我偶然发现了我的具体问题。我对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实例。在ServicePoint空闲了MaxIdleTime中指定的时间后,它有资格进行垃圾回收。当与ServicePoint关联的连接列表为空时,ServicePoint处于空闲状态。

对我而言,所有这一切的关键在于具体说明在服务点空闲达到最大空闲时间之后,它有资格进行垃圾收集。我已经看到从100秒到900秒的任何地方作为此值的默认值,具体取决于描述所涉及的框架版本。在我考虑这个问题之前,我会做更多的测试。我希望任何使用过这些属性的人来到这里来解决他们的具体问题,以及这是否是我所见过的问题的根本原因。

c# windows-ce httprequest httpresponse compact-framework
2个回答
1
投票

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

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

1
投票

请参考帖子中的Update3。由于列出的原因,这似乎解决了我的问题。谢谢你的回复。

© www.soinside.com 2019 - 2024. All rights reserved.