2011-08-18 13 views
9

RPM Heap CompareHttpRequest/HttpResponse Rò rỉ bộ nhớ? CF.NET 3,5 WIN CE 6,0

Tôi đã thử mọi thứ có thể để thoát khỏi những gì tôi nghĩ là một rò rỉ bộ nhớ với Lớp học HttpRequest hoặc HttpResponse trong CF.NET 3.5 chạy trên một thiết bị 6.0 Win CE. Tôi đang sử dụng chúng để giao tiếp với camera IP.

Dưới đây là mã hiện tại tôi đang sử dụng. Mã đang chạy trong một điều khiển tùy chỉnh trên một chuỗi với mức độ ưu tiên được đặt thành dưới mức bình thường và nền được đặt thành true. Có hai đối tượng điều khiển trên một trong các biểu mẫu của tôi.

tôi nói hiện tại vì tôi đã cố gắng yêu cầu async và hoán vị khác của mã dưới đây không có giảm tiêu thụ bộ nhớ:

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); 
     } 
    } 

Tôi đã cấu hình nó với RPM và như bộ nhớ phát triển, do đó, làm một butch của các đối tượng bắt nguồn từ cho không gian tên System.Net và không gian tên System.Threading, bao gồm một loạt các đối tượng thread và sync mà tôi không tạo ra.

Tôi đã đính kèm hình ảnh so sánh heap của ảnh chụp nhanh heap đầu tiên và cuối cùng.

Tôi đã đảm bảo sử dụng "sử dụng" và gọi xử lý trên tất cả các phần cho phép. Ngoài ra, tôi đảm bảo Huỷ bỏ yêu cầu khi hoàn tất. Tôi đã thấy điều này trong các ví dụ khác và nó được cho là để giải phóng tài nguyên kết nối, v.v.

Đây là phần lạ, sự rò rỉ chỉ xảy ra khi một thời gian chờ WebException bị ném nếu tôi không có máy ảnh kết nối. Với máy ảnh được kết nối, các thiết bị chạy trong nhiều ngày mà không tăng bộ nhớ. Ngoài ra, cả số byte được quản lý và tổng số byte đều tăng theo RPM nên tôi không nghĩ rằng đó là một rò rỉ không được sửa đổi. Cuối cùng, tôi đang cố gắng để có được hình ảnh từ máy ảnh nhanh nhất có thể. Tôi bắt đầu tự hỏi liệu tôi có không cho thời gian GC để thu thập hay không. Nhưng khi một bộ sưu tập xảy ra (tôi thấy số lượng bộ sưu tập tăng lên trong RPM) số byte được quản lý không giảm, nó chỉ tiếp tục tăng. Hy vọng rằng tôi đang làm một cái gì đó rất ngu ngốc và đây là một sửa chữa dễ dàng. Như mọi khi, bất kỳ trợ giúp hoặc đề xuất nào được đánh giá cao.

Thông tin bổ sung:

Hai đại biểu gọi từ thread camera như sau nếu nó có thể giúp biết:

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(); 
} 

INFO2 bổ sung:

Chỉ cần để hoàn thành các thông tin, dưới đây Tôi đã bao gồm OnPaint(), v.v. Tôi đã sử dụng để vẽ Bitmap vào màn hình cho máy ảnh:

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) 
{ 

} 

Cập nhật:

Đây là những gì tôi không nhận được. Vì HttpRequest chỉ là một đối tượng chứa thông tin và không thể đóng/hủy bỏ, và vì khi một WebException hết thời gian bị ném, HttpResponse vẫn là null (không thể đóng), những gì đang tham chiếu đến các tài nguyên được sử dụng để yêu cầu? Giải thích duy nhất là có một số tham chiếu được tổ chức bởi đối tượng HttpRequest khi Abort được gọi, nên giải phóng tài nguyên được sử dụng để thực hiện yêu cầu, những cái mà tôi thấy không được phục hồi trong RPM. Vì tôi gọi Abort() và vì đối tượng HttpRequest chỉ nằm trong phạm vi trong yêu cầu, tôi không thấy bất kỳ tài nguyên nào được tham chiếu không thể được thu thập.

Update2:

Vâng, tôi để cho nó chạy với các máy ảnh được kích hoạt và cho phép timeout để tiếp tục, sau đó tôi bị vô hiệu hóa các máy ảnh, loại bỏ những nỗ lực HttpRequest và timeout, và để cho nó chạy còn lại trong ngày . Vào cuối ngày, GC đã bị mắc kẹt ở cùng một giá trị (dựa trên thử nghiệm trước đây nó phải tăng khoảng 6MB), chứng minh rằng không có gì liên quan đến việc thu thập thời gian GC, ít nhất tôi nghĩ vậy. Vì vậy, các nguồn lực vẫn còn trong tình trạng lấp lửng và tôi cần phải tìm ra chính xác những gì đang giữ chúng bắt nguồn từ. Hy vọng rằng tôi có thể thấy rằng ra và đưa ra một bản cập nhật khác. Cho đến lúc đó ...

Side Lưu ý:

Có ai đã từng sử dụng HttpRequest/HttpResponse để có được hình ảnh từ camera IP, trên một thiết bị WIN CE sử dụng CF.NET 3.5? Nếu vậy, đã có một trường hợp thử nghiệm cho mất comm từ máy ảnh trong một khoảng thời gian không xác định? Đó chắc hẳn là điều đầu tiên tôi hỏi vì tôi không tìm thấy nhiều ví dụ ngoài kia cho thấy cách giao tiếp với camera IP từ các thiết bị nhúng.

Cập nhật3:

Vâng, tôi nghĩ rằng tôi đã vấp phải khắc phục sự cố cụ thể của mình. Tôi đã thực hiện một vài thay đổi cho các thành viên lớp ServicePointManager tĩnh đối với số lượng kết nối mặc định và thời gian nhàn rỗi tối đa với:

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

Vì tôi sẽ có tối đa 4 camera kết nối bất cứ lúc nào, và kể từ thời gian chờ của tôi cho HttpRequest được đặt là 5000 mili giây, tôi đã hình dung rằng tôi sẽ thử thời gian rỗi tối đa 1000ms để xem điều gì sẽ xảy ra. Tôi để hai thiết bị chạy qua đêm mà không có máy ảnh nào được kết nối (hết thời gian trên mỗi 5000ms). Điều thường xảy ra là tôi sẽ đến vào buổi sáng và các thiết bị sẽ ngồi đó với một tin nhắn OOM và bộ nhớ GC và bộ nhớ vật lý sẽ được maxed ra cho hệ thống của tôi. Vâng, cả hai thiết bị đều ở cùng mức độ bộ nhớ mà họ đã ở khi tôi rời đêm qua. Vì vậy, tôi hy vọng đây là bản sửa lỗi cho vấn đề của tôi. Dựa trên tài liệu MSDN:

Thuộc tính ConnectionLimit đặt số lượng kết nối tối đa mà ServicePoint có thể thực hiện cho tài nguyên Internet. Giá trị của thuộc tính ConnectionLimit được đặt thành giá trị của thuộc tính ServicePointManager.DefaultConnectionLimit khi ServicePoint được tạo; các thay đổi tiếp theo đối với DefaultConnectionLimit không có hiệu lực đối với các phiên bản ServicePoint hiện có.

Thuộc tính MaxIdleTime chứa khoảng thời gian, tính bằng mili giây, ServicePoint được phép duy trì kết nối không hoạt động với tài nguyên Internet trước khi được tái sử dụng trong kết nối khác. Bạn có thể đặt MaxIdleTime thành Timeout.Infinite để chỉ ra rằng ServicePoint sẽ không bao giờ hết thời gian chờ. Giá trị mặc định của thuộc tính MaxIdleTime là giá trị của thuộc tính ServicePointManager.MaxServicePointIdleTime khi ServicePoint được tạo. Các thay đổi tiếp theo đối với thuộc tính MaxServicePointIdleTime không ảnh hưởng đến các phiên bản ServicePoint hiện có.

Thuộc tính MaxServicePointIdleTime đặt thời gian nhàn rỗi tối đa mà ServicePointManager gán cho thuộc tính MaxIdleTime khi tạo các cá thể ServicePoint. Các thay đổi đối với giá trị này sẽ chỉ ảnh hưởng đến các phiên bản ServicePoint được khởi tạo sau khi giá trị được thay đổi. Sau khi ServicePoint không hoạt động trong khoảng thời gian được chỉ định trong MaxIdleTime, nó sẽ đủ điều kiện để thu thập rác. ServicePoint không hoạt động khi danh sách kết nối được liên kết với ServicePoint trống.

Chìa khóa để tất cả điều này đối với tôi là đó là đặc biệt khẳng định rằng sau khi điểm dịch vụ là nhàn rỗi trong thời gian nhàn rỗi max nó là đủ điều kiện để thu gom rác thải.Tôi đã thấy bất cứ nơi nào từ 100 giây đến 900 giây như là mặc định cho giá trị này, tùy thuộc vào phiên bản khuôn khổ mô tả đã được liên quan đến. Tôi sẽ làm một số thử nghiệm nhiều hơn trước khi tôi xem xét điều này một sửa chữa. Tôi rất thích ở đây từ bất cứ ai đã chơi với những tài sản này để sửa chữa các vấn đề cụ thể của họ và có hay không điều này có ý nghĩa như là nguyên nhân gốc rễ của vấn đề tôi đã được nhìn thấy. Tất cả các câu trả lời đều được đánh giá cao. Cảm ơn trước.

+0

Điều gì đang diễn ra trong 'RefreshDisplayDelegate'? – ctacke

+0

RefreshDisplayXác định điểm đến một phương thức chỉ cần gọi lại Làm mới() trên điều khiển nếu thời gian chờ xảy ra. Tôi vẽ một chuỗi trên bitmap cho biết máy ảnh đã mất dấu phẩy. Tôi đã thêm vào bài đăng gốc với hai đại biểu mà tôi gọi từ chuỗi. Cảm ơn vì sự trả lời. – CCS

Trả lời

1

Vui lòng tham khảo UPDATE3 trong bài viết. Điều này dường như đã khắc phục được sự cố của tôi vì những lý do được liệt kê. Cảm ơn bạn đã trả lời.

1

chỉ cần đặt các AllowWriteStreamBuffering tài sản của đối tượng HttpWebRequest bạn false:

HttpReq.AllowWriteStreamBuffering = false; 
HttpReq.AllowAutoRedirect = false; 
+0

Trong khung công tác nhỏ gọn, AllowWriteStreamBuffering được mặc định là false, nhưng AllowAutoRedirect thì không. Tôi sẽ cho nó nó một cơ hội. Tôi cũng nhận thấy rằng cờ KeepAlive được mặc định là true. Tại một thời điểm tôi đã có cả AllowWriteStreamBuffering và KeepAlive được đặt thành false và không có sự khác biệt. Tôi sẽ mặc định tất cả chúng thành false và xem nó hoạt động như thế nào. Cảm ơn vì sự trả lời. – CCS

+0

Vâng, điều đó không tạo nên sự khác biệt. Dù sao cũng cảm ơn bạn. – CCS