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