2009-09-24 48 views
15

Tôi có một đối tượng tồn tại mãi mãi. Tôi đang xóa tất cả các tham chiếu mà tôi có thể thấy, sau khi sử dụng nó, nhưng nó vẫn chưa được thu thập. Vòng đời của nó khá tinh vi nên tôi không thể chắc chắn rằng tất cả các tham chiếu đã bị xóa.Tìm tham chiếu đến đối tượng trong thời gian chạy

if (container.Controls.Count > 0) 
{ 
    var controls = new Control[ container.Controls.Count ]; 
    container.Controls.CopyTo(controls, 0); 

    foreach (var control in controls) 
    { 
     container.Controls.Remove(control); 
     control.Dispose(); 
    } 

    controls = null; 
} 

GC.Collect(); 
GC.Collect(1); 
GC.Collect(2); 
GC.Collect(3); 

Tôi làm cách nào để tìm hiểu tham chiếu nào? Tại sao nó không được thu thập?

+0

Hiển thị mã cho chúng tôi và chúng tôi có thể trợ giúp. Lưu ý rằng việc thu gom rác thải không nhất thiết xảy ra ngay lập tức. – Lazarus

+0

Và tôi đoán câu hỏi thực sự là, tại sao bạn lo lắng về nó? Nếu bạn đang sử dụng tài nguyên dùng một lần, vứt bỏ chúng khi bạn không sử dụng chúng nữa, hãy dọn sạch tài nguyên hệ thống không được quản lý và xem ra bằng chuỗi ký tự. –

+0

Mã này là: if (container.Controls.Count> 0) { \t \t \t \t var điều khiển = new kiểm soát [container.Controls.Count]; \t \t \t \t container.Controls.CopyTo (điều khiển, 0); \t \t \t \t foreach (var kiểm soát trong điều khiển) { \t \t \t \t \t container.Controls.Remove (đối chứng); \t \t \t \t \t control.Dispose(); \t \t \t \t \t \t \t \t \t} \t \t \t \t điều khiển = null; \t \t \t} GC.Collect(); GC.Collect (1); GC.Collect (2); GC.Collect (3); Nhưng nó vẫn còn trong bộ nhớ. Vì vậy, nó meens, rằng nó thép có nguồn gốc. Làm thế nào tôi có thể tìm thấy nguồn gốc này? –

Trả lời

11

Hãy thử sử dụng profiler bộ nhớ, (ví dụ: ants) nó sẽ cho bạn biết điều gì đang giữ cho đối tượng còn sống. Đang cố gắng đoán 2 loại vấn đề này là rất khó.

Cổng đỏ cho phép dùng thử 14 ngày nên có nhiều thời gian hơn để giải quyết vấn đề này và quyết định xem liệu trình thu thập bộ nhớ có cung cấp cho bạn giá trị lâu dài hay không.

nhiều của profilers bộ nhớ khác trên thị trường (ví dụ .NET Memory Profiler) hầu hết trong số họ có thử nghiệm miễn phí, tuy nhiên tôi đã phát hiện ra rằng Red-Gate công cụ rất dễ sử dụng, vì vậy có xu hướng thử chúng trước tiên.

+0

Cảm ơn, tôi sẽ cố gắng! –

+0

Họ cũng có một số video đào tạo miễn phí (và tài liệu), v.v. giải thích cách trình thu gom rác .net hoạt động mà bạn có thể thấy hữu ích. –

+0

@ er-v: đối tượng của bạn có thể đã được thu thập nhưng bộ nhớ có thể chưa được Windows thu hồi. Khung công tác không phải trả lại bộ nhớ cho hệ điều hành. – user7116

0

Nó không được thu thập vì bạn chưa xóa tất cả các tham chiếu đến nó. GC sẽ chỉ đánh dấu các đối tượng để thu thập nếu chúng không có rễ trong ứng dụng.

Bạn đang sử dụng phương tiện nào để kiểm tra GC để xem liệu nó có thu thập đối tượng của bạn không?

2

Bộ sưu tập rác trong .NET không phải là lược đồ đếm (chẳng hạn như COM), nhưng thực thi đánh dấu và quét. Về cơ bản, GC chạy ở thời gian "ngẫu nhiên" khi nó cảm thấy cần phải làm như vậy, và do đó việc thu thập các đối tượng không xác định.

Bạn có thể, tuy nhiên, kích hoạt thủ công một bộ sưu tập (GC.Collect()), nhưng bạn có thể phải đợi trình hoàn thành chạy sau đó (GC.WaitForPendingFinalizers()). Tuy nhiên, thực hiện điều này trong một ứng dụng sản xuất không được khuyến khích vì nó có thể ảnh hưởng đến hiệu quả của việc quản lý bộ nhớ (GC chạy quá thường xuyên, hoặc chờ các finalizers chạy). Nếu đối tượng vẫn còn tồn tại, nó thực sự vẫn có một số tham chiếu trực tiếp ở đâu đó.

3

Bạn sẽ phải sử dụng tiện ích mở rộng WindbgSosex.

Các lệnh !DumpHeap!GCRoot có thể giúp bạn xác định cá thể và tất cả các tham chiếu còn lại giữ cho nó luôn hoạt động.

3

Tôi đã sử dụng .NET Memory Profiler để thực hiện một số hồ sơ bộ nhớ nghiêm trọng trên một trong các dự án của chúng tôi. Đó là một công cụ tuyệt vời để xem xét việc quản lý bộ nhớ của ứng dụng của bạn. Tôi không được trả tiền cho thông tin này :) nhưng nó chỉ giúp tôi rất nhiều.

+0

Đồng ý, nó là một công cụ rất hữu ích, đặc biệt là các công cụ trực quan. –

3

Tôi đã giải quyết vấn đề tương tự với phần mở rộng SOS (dường như không còn hoạt động với Visual Studio 2013, nhưng hoạt động tốt với các phiên bản cũ hơn của Visual Studio).

tôi đã sử dụng mã sau đây để có được địa chỉ của đối tượng mà tôi muốn theo dõi tham khảo:

public static string GetAddress(object o) 
{ 
    if (o == null) 
    { 
     return "00000000"; 
    } 
    else 
    { 
     unsafe 
     { 
      System.TypedReference tr = __makeref(o); 
      System.IntPtr ptr = **(System.IntPtr**) (&tr); 
      return ptr.ToString ("X"); 
     } 
    } 
} 

và sau đó, trong Visual Studio 2012 cửa sổ ngay lập tức, trong khi chạy trong trình gỡ lỗi, gõ:

.load C:\Windows\Microsoft.NET\Framework\v4.0.30319\sos.dll 

sẽ tải tiện ích mở rộng SOS.dll.

Sau đó bạn có thể sử dụng GetAddress(x) để lấy địa chỉ thập lục phân của đối tượng (ví dụ 8AB0CD40), và sau đó sử dụng:

!do 8AB0CD40 
!GCRoot -all 8AB0CD40 

để đổ đối tượng và tìm thấy tất cả các tài liệu tham khảo cho các đối tượng.

Chỉ cần nhớ rằng nếu GC chạy, nó có thể thay đổi địa chỉ của đối tượng.

Các vấn đề liên quan