2016-02-12 14 views
9

Tôi hiểu rằng các điều tra viên và từ khóa lợi nhuận có thể được sử dụng để trợ giúp các hoạt động không đồng bộ/so le, vì bạn có thể gọi MoveNext() để chạy khối mã tiếp theo.GC hoạt động như thế nào với IEnumerator và năng suất?

Tuy nhiên, tôi không thực sự hiểu đối tượng Đếm đó là gì. Bộ nhớ trong việc sử dụng phạm vi của Điều tra viên đi đâu? Nếu bạn không MoveNext() một điều tra viên tất cả các cách, nó có được GC cuối cùng? Về cơ bản, tôi đang cố gắng giảm số lần truy cập GC, vì tôi có khả năng sử dụng rất nhiều bảng liệt kê và GC có thể là một vấn đề bên trong Unity, đặc biệt là do phiên bản cũ hơn của Mono nó sử dụng.

Tôi đã cố gắng để hồ sơ này nhưng không thể quấn đầu của tôi xung quanh họ vẫn còn. Tôi không hiểu phạm vi/tham chiếu xảy ra với các Điều tra viên. Tôi cũng không hiểu nếu Enumerators được tạo ra như là đối tượng khi bạn tạo một từ một chức năng sản lượng.

Ví dụ sau đây cho thấy sự nhầm lẫn của tôi tốt hơn:

// Example enumerator 
IEnumerator<bool> ExampleFunction() 
{ 
    SomeClass heavyObject = new SomeClass(); 
    while(heavyObject.Process()) 
    { 
     yield return true; 
    } 

    if(!heavyObject.Success) 
    { 
     yield return false; 
    } 

    // In this example, we'll never get here - what happens to the incomplete Enumerator 
    // When does heavyObject get GC'd? 
    heavyObject.DoSomeMoreStuff(); 
} 

// example call - Where does this enumerator come from? 
// Is something creating it with the new keyword in the background? 
IEnumerator<bool> enumerator = ExampleFunction(); 
while(enumerator.MoveNext()) 
{ 
    if(!enumerator.Current) 
    { 
     break; 
    } 
} 

// if enumerator is never used after this, does it get destroyed when the scope ends, or is it GC'd at a later date? 
+4

Trình biên dịch viết lại phương pháp liệt kê của bạn và di chuyển mã vào một lớp với tên không thể nói. Lớp này thực hiện một máy trạng thái nơi các biến cục bộ của bạn trở thành các trường của lớp, cho phép MoveNext() được nhập lại mà không làm mất trạng thái. Tham chiếu giao diện IEnumerator thực sự là một tham chiếu đến một đối tượng của lớp đó. Mọi thứ sẽ không tồn tại khi tham chiếu đó được thu thập, đủ điều kiện để được GC-ed ngay sau khi mã của bạn rời khỏi vòng lặp foreach. –

+5

Ví dụ về những gì Hans đã nói: http://goo.gl/fs4eNo – xanatos

+0

OK, cảm ơn. Điều đó không làm những gì tôi mong đợi ở TẤT CẢ. Điều đó có nghĩa là ĐTV có khá nặng so với các phương tiện truyền thống không? Tôi đang cố gắng để giữ GC xuống nhưng có vẻ như tôi sẽ tạo ra rác mới bất cứ lúc nào tôi bắt đầu một Enumerator mới (và tôi có rất nhiều điều tra viên). – mGuv

Trả lời

5

Có thể bạn nên đọc bài viết nội bộ của người điều tra. Từ nội bộ, bạn có thể trả lời tất cả các câu hỏi này.

Khoá học lỗi: Mỗi lần thực thi phương thức lặp lại trả về đối tượng điều tra mới. Biến cục bộ trở thành trường.

Nếu không ai sử dụng đối tượng điều tra đó nữa thì nó đủ điều kiện để thu thập. Ngoài ra, tất cả các tham chiếu mà các biến cục bộ đã tạo ra biến mất cho mục đích GC.

Có một số trường hợp cạnh khi các biến cục bộ chính xác dừng tham chiếu GC. Nếu các điều tra viên của bạn khá ngắn ngủi thì điều này không quan trọng lắm.

CLR không biết điều tra viên là gì. Nó chỉ là một lớp được tạo bởi trình biên dịch C#.

Kéo liên kết bởi xanatos vào câu trả lời này vì nó minh họa và ông dường như không gửi một câu trả lời: http://goo.gl/fs4eNo

+0

Phải, điều đó giải thích rất nhiều. Tôi không biết có bao nhiêu sự tự động mà nó đã làm khi nó đến với những người điều tra. Tôi có rất nhiều phương thức trả lại các Điều tra viên và tôi có rất nhiều thứ gọi/sử dụng chúng. Điều này nghe có vẻ như nó có thể là một vấn đề GC, như mọi Enumerator đến để tồn tại sẽ cần GCing. Nó sẽ phải là một cái gì đó tôi hồ sơ. – mGuv

2

Các điều tra viên được quản lý theo cùng một cách như mọi trường hợp quản lý khác - khi nó được ra khỏi phạm vi. Vì vậy, nếu MoveNext() không bao giờ được gọi là xóa GC (hoặc đánh dấu nó tốt hơn để xóa) điều tra viên khi nó nằm ngoài phạm vi của nó. Việc lặp lại một điều tra viên không xảy ra ở bất kỳ song song nào, do đó cả việc thực hiện và thu gom rác đều chạy một cách xác định và liên tục khi bạn thực hiện với nó.

Khi bên trong một phương thức vòng lặp, yield-return -stament không phải là câu cuối cùng, nó chỉ đơn giản có nghĩa là khi MoveNext() được gọi là kết quả hiện tại sẽ được trả về. Tuy nhiên, mọi thứ phía sau yield return đều chạy sau khi gọi tới số MoveNext, do đó, bạn cũng có thể gọi tới số DoSomeMoreStuff.

Tuy nhiên, heavyObject của bạn có phạm vi của phương thức, do đó, nó tồn tại miễn là trình lặp - nơi trình vòng lặp là khối bên trong vòng lặp while của bạn. Điều này có nghĩa là nếu trình lặp của bạn thậm chí không trả về bất kỳ cá thể nào heavyObject sẽ được xử lý ngay lập tức, nếu không khi lặp lại đã kết thúc.

3

// nếu điều tra viên không bao giờ được sử dụng sau đó, nó được tiêu huỷ khi phạm vi kết thúc

đúng

Điều kiện để thu được không có tài liệu tham khảo. Đối với phạm vi của GC không có gì đặc biệt với các điều tra viên. Các điều tra viên được xử lý/xóa bỏ theo cách tương tự khi chúng vượt ra khỏi phạm vi như bất kỳ loại nào khác.

+0

Nếu một điều tra viên không bao giờ tham khảo ở bất cứ nơi nào, nhưng tại địa phương từ bên trong một chức năng, nó có được GC'd rẻ/ngay lập tức? Tôi không hoàn toàn hiểu GC nhưng tôi biết rằng vì nó không thể được tham chiếu bất cứ nơi nào nhưng bên trong chức năng, nó khá thẳng về phía trước để phát hiện rằng nó có thể được làm sạch? – mGuv

+0

Vâng, đó là Chính xác. – CharithJ

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