2012-01-11 29 views
11

Tất cả!Mã lạ trong java.util.concurrent.LinkedBlockingQueue

Tôi tìm thấy mã lạ trong LinkedBlockingQueue:

private E dequeue() { 
     // assert takeLock.isHeldByCurrentThread(); 
     Node<E> h = head; 
     Node<E> first = h.next; 
     h.next = h; // help GC 
     head = first; 
     E x = first.item; 
     first.item = null; 
     return x; 
} 

Ai có thể giải thích tại sao chúng ta cần phải biến cục bộ h? Làm thế nào nó có thể giúp cho GC?

+0

có thể nhận xét là đã lỗi thời (bạn có thể tìm thấy sự kiểm soát phiên bản và theo dõi các bình luận cho cam?) :) – milan

+2

Thật thú vị rằng đây var tạm thời và bình luận được thêm vào chỉ trong java 7. Vì vậy, nó đã được definitively bởi một số ý định. Xem http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/util/concurrent/LinkedBlockingQueue.java#LinkedBlockingQueue.extract%28%29 và http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/7-b147/java/util/concurrent/LinkedBlockingQueue.java#LinkedBlockingQueue.dequeue%28%29 – Vadzim

+0

đó là openjdk, LinkedBlockingQueue trong Oracle jdk 6 trên máy Mac (1.6.0_29-b11-402.jdk) có biến tạm thời. – milan

Trả lời

1

Để hiểu rõ hơn điều gì xảy ra, hãy xem danh sách trông như thế nào sau khi thực thi mã. Đầu tiên hãy xem xét một danh sách ban đầu:

1 -> 2 -> 3 

Sau đó h điểm để headfirst-h.next:

1 -> 2 -> 3 
| | 
h first 

Sau đó h.next điểm để hhead điểm để first:

1 -> 2 -> 3 
| /\ 
h head first 

Bây giờ, thực tế chúng ta biết rằng ere chỉ là tham chiếu đang hoạt động trỏ đến phần tử đầu tiên, là chính nó (h.next = h), và chúng ta cũng biết rằng GC thu thập các đối tượng không có tham chiếu hoạt động nhiều hơn, vì vậy khi phương thức kết thúc, đầu (cũ) của danh sách ca được GC thu thập một cách an toàn vì h chỉ tồn tại trong phạm vi của phương pháp.

Nói xong, nó đã được chỉ ra, và tôi đồng ý với điều này, mà ngay cả với phương pháp dequeue cổ điển (tức là chỉ cần đảm first điểm đến head.nexthead điểm đến first) không có nhiều tài liệu tham khảo chỉ tay về phía người đứng đầu cũ . Tuy nhiên, trong trường hợp này, đầu cũ bị treo lơ lửng trong bộ nhớ và vẫn có trường next trỏ về phía first, trong khi mã bạn đăng, điều duy nhất còn lại là một đối tượng bị cô lập trỏ đến chính nó. Điều này có thể kích hoạt GC để hoạt động nhanh hơn.

+0

Việc hủy bỏ nguyên nhân h sẽ không còn tham chiếu nữa ngay cả khi không có 'h.next = h'. – Vadzim

+1

@Vadzim: Tôi không nói rõ điều đó, tôi chỉ giải thích những gì xảy ra trong mã mà anh ta đăng. – Tudor

+0

Câu hỏi không phải là về điều đó. Đó là về lý do tại sao không chỉ 'first = head = head.next'. Nhưng cảm ơn cho đồ họa anyway. Lưu ý rằng đầu luôn không chứa mục đầu tiên. – Vadzim

0

Đây là mẫu mã minh họa câu hỏi: http://pastebin.com/zTsLpUpq. Thực hiện một GC sau runWith() và lấy một vùng lưu trữ vùng heap cho cả hai phiên bản cho biết chỉ có một đối tượng Item.

+0

Vậy "trợ giúp" cho GC là gì? – Vadzim

+0

có thể trong một số tình huống, tôi không biết, có lẽ chúng tôi có thể tìm thấy người đã viết nhận xét :) – milan

4

Có thể hơi muộn, nhưng lời giải thích hiện tại hoàn toàn không đạt yêu cầu đối với tôi và tôi nghĩ rằng tôi đã có một giải thích hợp lý hơn.

Trước hết, mọi GC thực hiện một số loại truy tìm từ bộ gốc theo cách này hay cách khác. Điều này có nghĩa rằng nếu người đứng đầu cũ được thu thập, chúng tôi sẽ không đọc biến số next dù sao đi nữa - không có lý do gì để làm như vậy. Do đó NẾU đầu được thu thập trong lần lặp tiếp theo, điều đó không quan trọng.

IF trong câu trên là phần quan trọng ở đây. Sự khác biệt giữa thiết lập bên cạnh thứ gì đó khác nhau không quan trọng đối với việc thu thập chính nó, nhưng có thể tạo sự khác biệt cho các đối tượng khác.

Giả sử một GC thế hệ đơn giản: Nếu đầu nằm trong tập hợp trẻ, nó sẽ được thu thập trong GC tiếp theo dù sao đi nữa. Nhưng nếu nó ở trong bộ cũ, nó sẽ chỉ được thu thập khi chúng ta thực hiện một GC đầy đủ, điều hiếm khi xảy ra.

Vậy điều gì sẽ xảy ra nếu đầu nằm trong nhóm cũ và chúng tôi làm một GC trẻ?Trong trường hợp này JVM giả định rằng mọi đối tượng trong heap cũ vẫn còn sống và thêm mọi tham chiếu từ cũ sang các đối tượng trẻ vào bộ gốc cho GC trẻ. Và đó chính là điều mà nhiệm vụ tránh ở đây: Viết vào heap cũ thường được bảo vệ bằng hàng rào viết hoặc thứ gì đó để JVM có thể nắm bắt các nhiệm vụ đó và xử lý chúng một cách chính xác - trong trường hợp của chúng tôi, nó xóa đối tượng next được trỏ đến từ bộ gốc mà không có hậu quả.

Ví dụ ngắn:

Giả sử chúng tôi có 1 (old) -> 2 (young) -> 3 (xx). Nếu chúng tôi xóa 1 và 2 ngay từ danh sách của mình, chúng tôi có thể mong đợi rằng cả hai yếu tố sẽ được thu thập bởi GC tiếp theo. Nhưng nếu chỉ có một GC trẻ xảy ra và chúng tôi đã không loại bỏ các con trỏ next trong cũ, cả hai yếu tố 1 và 2 sẽ không được thu thập. Trái ngược với điều này nếu chúng tôi đã loại bỏ các con trỏ trong 1, 2 sẽ được thu thập bởi các GC trẻ ..

+0

Tôi thực sự không thấy bất kỳ sự khác biệt giữa những gì bạn đang nói và những gì tôi đã nói. Tôi cũng nói rằng không loại bỏ tiếp theo có thể làm cho GC thu thập đầu nhanh hơn. – Tudor

+1

@Tudor Vâng tôi đã giải thích cơ chế nào sẽ gây ra thay đổi trong hành vi và trong hoàn cảnh nào nó sẽ xảy ra, điều đó chắc chắn có vẻ quan trọng hơn tôi "điều gì đó có thể khiến GC hành động khác". Ngoài ra nó không phải là về đầu được thu thập trước đó (như đó là rõ ràng là vô nghĩa), nhưng về các yếu tố tiếp theo - các đối tượng khác nhau được. – Voo

+0

Tôi đã nói trong nhận xét của mình rằng trong trường hợp không có triển khai thực tế, tôi chỉ có thể suy đoán về nhiệm vụ đó được cho là phải làm gì. Mặt khác, bạn đã thực hiện khá nhiều tuyên bố tuyệt đối mà không thực sự cung cấp bất kỳ nguồn nào và các thuật ngữ được sử dụng như "GC trẻ" mà không thực sự giới thiệu chúng. – Tudor

6

Nếu bạn nhìn vào src jsr166 sau đó bạn sẽ tìm thấy những vi phạm cam kết

http://gee.cs.oswego.edu/cgi-bin/viewcvs.cgi/jsr166/src/main/java/util/concurrent/LinkedBlockingQueue.java?view=log (thấy v 1,51)

Điều này cho thấy câu trả lời là trong báo cáo lỗi này

http://bugs.sun.com/view_bug.do?bug_id=6805775

các cuộc thảo luận đầy đủ là trong chủ đề này

http://thread.gmane.org/gmane.comp.java.jsr.166-concurrency/5758

Bit "trợ giúp GC" là để tránh những thứ bị chảy máu vào người thuê.

Cheers

Matt