2011-01-21 45 views
5

Tôi đang sử dụng đối tượng COM từ .NET bằng cách sử dụng interop. Đối tượng cơ bản lấy dữ liệu từ ổ cắm và kích hoạt một số sự kiện cho lớp .NET để xử lý. Tuy nhiên, sau một thời gian, đối tượng COM ngừng kích hoạt các sự kiện được tiết lộ sau đó bởi vì nó được GC thu thập.Đối tượng COM này có bị thu gom rác không?

Cấu trúc của mã nguồn tương tự như một dưới đây:

static void Main(string[] args) 
{ 
    MyEventGen gen = new MyEventGen(); 
    WeakReference wr = new WeakReference(gen); 
    gen.ReceiveDataArray += 
      new _IMyEventGenEvents_ReceiveDataArrayEventHandler(gen_ReceiveDataArray); 
    while (true) 
    { 
     Thread.Sleep(1000); 
     Console.WriteLine(wr.IsAlive); 
    } 
} 

static void gen_ReceiveDataArray(ref Array indices, ref Array values) 
{ 
    // do nothing 
} 

alt text

Những gì tôi biết cho đến nay:

  • Từ những gì tôi hiểu, đối tượng gen shouldn không được thu gom rác theo bất kỳ cách nào. Vì đối tượng vẫn hoạt động trong phạm vi Main. Nhưng kết quả cho đến nay cho thấy rằng đối tượng được thu thập bởi GC.

  • Đối tượng chỉ được thu gom rác khi được xây dựng dưới dạng Nhả và chạy mà không cần gỡ lỗi. Chạy Debug xây dựng/chạy cả hai chế độ theo trình gỡ lỗi là tốt.

  • Chương trình sẽ in chữ "False" đầu tiên chính xác sau Bộ sưu tập đầu tiên của bộ sưu tập # 0.

  • Bằng cách truy cập đối tượng trong vòng lặp while, ví dụ: Console.WriteLine(gen.ToString()), ngăn không cho nó bị GC!

  • Bằng cách thêm một trường tĩnh khác là Program lớp để giữ tham chiếu của nó cũng ngăn không cho GC.

  • Đang thử với tải dữ liệu khác nhau, tôi nhận thấy GC chỉ thu thập đối tượng khi Private byte đạt ngưỡng trên ~ 3X MB.

  • Kiểm tra với CLRProfiler, đối tượng được đề cập là GC bị nghi ngờ.

Tôi đã bỏ lỡ một số khái niệm quan trọng của .NET GC chưa? Có thể có được lý do cho đối tượng là GC'd? Đây có phải là một lỗi GC đã biết không?

Tôi đang sử dụng VS 2008 + .NET 3.5 SP1. Đánh giá cao suy nghĩ của bạn. Cảm ơn!

Trả lời

6

Không cần phải sử dụng đối tượng COM để tạo lại điều này. Hãy xem xét những điều sau:

public class MyEventGen 
{ 
    public event Action ReceiveDataArray; 
} 

class Program 
{ 
    public static void Main() 
    { 
     var gen = new MyEventGen(); 
     var wr = new WeakReference(gen); 
     // this is the last time we access the 
     // gen instance in this scope so after this line it 
     // is eligible for garbage collection 
     gen.ReceiveDataArray += new Action(gen_ReceiveDataArray); 

     // run the collector 
     GC.Collect(); 
     while (true) 
     { 
      Thread.Sleep(1000); 
      Console.WriteLine(wr.IsAlive); 
     } 
    } 

    static void gen_ReceiveDataArray() 
    { 
    } 
} 

Chạy trong chế độ Phát hành và nó sẽ có cùng hành vi. Các đối tượng gen rơi ra khỏi phạm vi và là rác thu thập bởi vì không có gì để giữ cho nó sống trong quá trình thực hiện vòng lặp.

+0

Cảm ơn Darin! Có vẻ như tôi hiểu lầm quá trình GC tất cả những năm này: ') – Gant

+1

@ m3rLinEz, điều ở chế độ Release nhiều tối ưu hóa được thực hiện và GC có thể trở nên thực sự tích cực. Nó có khả năng hiểu rằng biến 'gen' không còn được sử dụng sau lần truy cập cuối cùng và nó được thu thập. Giữ gen như một biến tĩnh nên ngăn chặn điều này xảy ra. –

2

Không gen cũng không wr vẫn hoạt động trong Phạm vi chính khi thực hiện vòng lặp while của bạn. Bạn đã đính kèm ba dòng đầu tiên trong dấu ngoặc ôm đặt các biến đó trong phạm vi con được thoát trước khi bắt đầu vòng lặp while của bạn.

+0

Tôi nghĩ đây không phải là trường hợp. Tôi nghĩ rằng niềng răng là một lỗi đánh máy, nếu không chương trình của anh ta sẽ không biên dịch vì anh ta sẽ không thể truy cập biến 'wr' trong vòng lặp while và có thể in False. –

+0

Cảm ơn. Tôi đã sửa lỗi chính tả. – Gant

+1

Thậm chí phạm vi không đủ để giữ cho các đối tượng còn sống: đó là nơi các đối tượng được sử dụng để đếm (mặc dù trình gỡ lỗi VS giữ các đối tượng còn sống cho đến khi kết thúc phạm vi của chúng). Bạn có thể nhận được bất ngờ trong bản phát hành Bản phát hành nơi các đối tượng được thu thập ở giữa phương thức hoặc thậm chí là một phần thông qua một dòng mã. –

2

Đối tượng COM của bạn đủ điều kiện để hủy ngay sau khi các tương đương .NET của chúng biến mất khỏi chương trình. Lần cuối cùng gen được sử dụng khi thực hiện cuộc gọi ReceiveDataArray += ....

Bạn nên thêm cuộc gọi vào GC.KeepAlive(gen) tại thời điểm trong chương trình có thể chấp nhận để dọn dẹp. Ngoài ra, nếu nó cần để sống cho đến khi chương trình thoát, bạn có thể thêm nó như là một trường static.

+0

Cảm ơn Tim! Chỉ cần để xác nhận, vì vậy tôi không thể biết nếu một đối tượng tham chiếu bởi biến địa phương sẽ sống cho đến khi kết thúc ''} ''cú đúp, đánh dấu sự kết thúc phạm vi của nó? – Gant

+0

Điều đó là chính xác: nó sẽ tồn tại khi nó được sử dụng tích cực bởi bất kỳ mã được quản lý nào, nhưng có thể biến mất bất kỳ lúc nào sau đó. Chỉ cần được gán cho một biến không được tính là 'đã sử dụng': biến đó phải được đề cập thấp hơn trong cùng một phương thức để đối tượng trong đó được giữ nguyên. –

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