2012-03-29 21 views
17

Tôi có hai bộ đệm riêng biệt chạy trong một JVM (một bộ điều khiển bởi một thư viện của bên thứ ba), mỗi bộ đều sử dụng các tham chiếu mềm. Tôi muốn cho JVM xóa bộ nhớ cache được kiểm soát của tôi trước khi bộ điều khiển được kiểm soát bởi thư viện. Trạng thái SoftReference javadoc:SoftReferences thu thập bởi JVM trong thực tế như thế nào?

Tất cả các tham chiếu mềm đối với các đối tượng dễ tiếp cận được đảm bảo đã xóa trước khi máy ảo ném OutOfMemoryError. Nếu không, không có ràng buộc nào được đặt vào thời điểm tham chiếu mềm sẽ bị xóa hoặc thứ tự trong đó một bộ tham chiếu như vậy đối với các đối tượng khác nhau sẽ bị xóa. Tuy nhiên, máy ảo hiện thực được khuyến khích thiên vị đối với việc xóa các tham chiếu mềm được tạo gần đây hoặc được sử dụng gần đây.

Các phiên bản trực tiếp của lớp này có thể được sử dụng để triển khai bộ đệm đơn giản; lớp này hoặc lớp con có nguồn gốc cũng có thể được sử dụng trong dữ liệu lớn hơn cấu trúc để triển khai bộ đệm tinh vi hơn. Miễn là tham chiếu của tham chiếu mềm có thể truy cập mạnh, nghĩa là, là thực sự đang được sử dụng, tham chiếu mềm sẽ không bị xóa. Do đó, ví dụ: bộ nhớ cache phức tạp có thể ngăn các mục nhập được sử dụng gần đây nhất của bạn bị loại bỏ bằng cách giữ các tham chiếu mạnh mẽ cho các mục nhập này, để các mục còn lại bị hủy bỏ theo yêu cầu của bộ thu gom rác.

Cách triển khai JVM chung, đặc biệt là HotSpot, xử lý SoftReferences trong thực tế? Họ có "thiên vị chống lại việc xóa các tham chiếu mềm được tạo gần đây hoặc được sử dụng gần đây" như được khuyến khích bởi thông số kỹ thuật không?

+0

có liên quan? [Cách điểm phát sóng quyết định Clear SoftReferences] (http://jeremymanson.blogspot.com/2009/07/how-hotspot-decide-to-clear_07.html) –

+1

@MiserableVariable Có, khá liên quan, mặc dù liên kết của bạn thiếu một chữ cái : http://jeremymanson.blogspot.com/2009/07/how-hotspot-decides-to-clear_07.html –

+0

Nó không thiếu nó trước đó nhưng tôi đã phải hành động thông minh và tạo ra một liên kết từ nó .. Vì Tôi từ chối đọc tài liệu và muốn làm điều đó bằng cách dùng thử và lỗi một số nội dung thực sự bị xóa đôi khi. Ai quan tâm, miễn là nó trông đẹp, phải không? –

Trả lời

6

Có vẻ như nó có thể điều chỉnh được, nhưng không phải vậy. Bộ thu thập quét đánh dấu đồng thời treo trên thực hiện mặc định của heap là must_clear_all_soft_refs() mà dường như chỉ là true khi thực hiện _last_ditch_collection.

bool GenCollectedHeap::must_clear_all_soft_refs() { 
    return _gc_cause == GCCause::_last_ditch_collection; 
} 

Trong khi xử lý bình thường của việc phân bổ không có ba cuộc gọi liên tiếp đến phương pháp của đống do_collect, trong CollectorPolicy.cpp

HeapWord* GenCollectorPolicy::satisfy_failed_allocation(size_t size, 
                bool is_tlab) { 

Những cố gắng để thu thập, cố gắng phân bổ lại, cố gắng mở rộng đống nếu thất bại , và sau đó như là một nỗ lực cuối cùng, cố gắng thu thập các tài liệu tham khảo mềm.

Các bình luận về bộ sưu tập cuối cùng là khá nói (và là người duy nhất gây nên thanh toán bù trừ refs mềm)

// If we reach this point, we're really out of memory. Try every trick 
    // we can to reclaim memory. Force collection of soft references. Force 
    // a complete compaction of the heap. Any additional methods for finding 
    // free memory should be here, especially if they are expensive. If this 
    // attempt fails, an OOM exception will be thrown. 
    { 
    IntFlagSetting flag_change(MarkSweepAlwaysCompactCount, 1); // Make sure the heap is fully compacted 

    gch->do_collection(true    /* full */, 
         true    /* clear_all_soft_refs */, 
         size    /* size */, 
         is_tlab   /* is_tlab */, 
         number_of_generations() - 1 /* max_level */); 
    } 

--- Chỉnh sửa để đáp ứng với sự thật hiển nhiên, tôi đã mô tả tài liệu tham khảo yếu, những người không mềm ---

Trong thực tế, tôi sẽ tưởng tượng rằng SoftReferences chỉ "không" được theo sau khi JVM được gọi để thu thập rác để phản hồi lại khi chúng cố gắng tránh OutOfMemoryError.

Đối với SoftReference s để tương thích với tất cả bốn bộ thu gom rác Java 1.4 và với bộ thu G1 mới, quyết định phải nằm chỉ với xác định khả năng kết nối. Vào thời điểm gặt hái và nén chặt xảy ra, đã quá muộn để quyết định liệu một vật thể có thể tiếp cận được hay không.Điều này cho thấy (nhưng không yêu cầu) rằng một bộ sưu tập "bối cảnh" tồn tại mà xác định khả năng tiếp cận dựa trên sự sẵn có bộ nhớ miễn phí trong heap. Một bối cảnh như vậy sẽ phải chỉ ra không theo dõi SoftReference s trước khi cố gắng theo dõi chúng.

Kể từ khi OutOfMemoryError thu gom rác tránh được lập lịch đặc biệt theo cách thu thập đầy đủ, tạm dừng, sẽ không khó tưởng tượng được trường hợp người quản lý heap đặt cờ "không theo dõi SoftReference" trước bộ sưu tập xảy ra.

--- Ok, vì vậy tôi quyết định rằng một "phải làm việc theo cách này" trả lời chỉ là không đủ tốt ---

Từ mã nguồn src/share/vm/gc_implementation/concurrentMarkSweep/vmCMSOperations.cpp (nổi bật là của tôi)

Các hoạt động để thực sự "làm" thu gom rác thải:

170 void VM_GenCollectFullConcurrent::doit() { 

Chúng tôi tốt hơn là một chủ đề VM, nếu không một luồng "chương trình" là thu gom rác!

171 assert(Thread::current()->is_VM_thread(), "Should be VM thread"); 

Chúng tôi là một nhà sưu tập đồng thời, vì vậy chúng tôi sẽ được lên lịch đồng thời tốt hơn!

172 assert(GCLockerInvokesConcurrent || ExplicitGCInvokesConcurrent, "Unexpected"); 
    173 

Lấy đống (có đối tượng GCCause trong đó).

174 GenCollectedHeap* gch = GenCollectedHeap::heap(); 

Hãy kiểm tra để xem liệu chúng ta cần một tiền cảnh "trẻ" bộ sưu tập

175 if (_gc_count_before == gch->total_collections()) { 
    176  // The "full" of do_full_collection call below "forces" 
    177  // a collection; the second arg, 0, below ensures that 
    178  // only the young gen is collected. XXX In the future, 
    179  // we'll probably need to have something in this interface 
    180  // to say do this only if we are sure we will not bail 
    181  // out to a full collection in this attempt, but that's 
    182  // for the future. 

Là những chủ đề chương trình không can thiệp với đống?

183  assert(SafepointSynchronize::is_at_safepoint(), 
    184  "We can only be executing this arm of if at a safepoint"); 

Lấy nguyên nhân thu gom rác (lý do cho bộ sưu tập này) từ đống.

185  GCCauseSetter gccs(gch, _gc_cause); 

Làm một bộ sưu tập đầy đủ các không gian trẻ

Lưu ý rằng đèo mình về giá trị của must_clear_all_soft_refs của đống cờ nào trong một kịch bản OutOfMemory phải được thiết lập là true, và trong cả hai trường hợp chỉ đạo các "do_full_collection" để không làm theo các tài liệu tham khảo mềm

186  gch->do_full_collection(gch->must_clear_all_soft_refs(), 
    187        0 /* collect only youngest gen */); 

các _gc_cause là một enum, đó là (phỏng đoán đây) thiết lập để _allocation_failure trong nỗ lực đầu tiên tại tránh OutOfMemoryError_last_ditch_collection sau thất bại (để cố gắng thu thập rác thoáng qua)

Một cái nhìn nhanh chóng trong memory "heap" module cho thấy rằng trong do_full_collection trong đó kêu gọi do_collection tài liệu tham khảo mềm bị xóa một cách rõ ràng (theo "đúng "điều kiện) với dòng

480 ClearedAllSoftRefs casr(do_clear_all_soft_refs, collector_policy()); 

--- Original post sau cho những ai muốn tìm hiểu về tài liệu tham khảo yếu ---

Trong Mark và Sweep thuật toán, tài liệu tham khảo mềm là không phải tiếp theo từ chuỗi Chính (và do đó không được đánh dấu trừ khi một nhánh khác có thể tiếp cận nó thông qua các tham chiếu không phải là phần mềm.

Trong thuật toán sao chép, tham chiếu mềm đối tượng trỏ đến là không được sao chép 01 () (trừ khi chúng được tiếp cận bằng tham chiếu không mềm khác).

Về cơ bản, khi theo dõi web tham chiếu từ chuỗi thực thi "chính", các tham chiếu mềm là không được theo dõi. Điều này cho phép các đối tượng của họ được thu gom rác như thể họ không có tài liệu tham khảo trỏ đến chúng.

Điều quan trọng cần lưu ý là các tham chiếu mềm gần như là không bao giờ được sử dụng riêng biệt. Chúng thường được sử dụng trong các đối tượng trong đó thiết kế có nhiều tham chiếu đến đối tượng, nhưng chỉ cần xóa một tham chiếu để kích hoạt thu gom rác (để dễ duy trì vùng chứa hoặc chạy hiệu suất thời gian không cần tìm kiếm tài liệu tham khảo đắt tiền) .

+1

Có vẻ như bạn đang mô tả các tham chiếu yếu hơn là các tham chiếu mềm. –

+0

@DaveL. Thế là đủ cho tôi tối nay. Nếu bạn cần câu trả lời cụ thể hơn, chúng có thể khá gần trong tham chiếu mã JVM ở trên. –

+0

Edwin, cảm ơn vì đã nghiên cứu. Nếu tôi hiểu chính xác, điều này cho thấy rằng nó sẽ xóa tất cả các tham chiếu mềm trong một kịch bản OutOfMemory, điều này chắc chắn có ý nghĩa. Câu hỏi sau đó là nó vẫn sẽ rõ ràng một số ngay cả khi lá cờ đó là không có ý nghĩa. Câu hỏi thường gặp về HotSpot và blog của Jerermy Manson cho biết thuật toán cho điều đó cũng xảy ra. –

3

Bất kể câu trả lời là gì, dựa vào một chiến lược cụ thể sẽ làm cho phần mềm của bạn không đáng tin cậy vì mọi triển khai JVM có thể khác nhau. Ngay cả đối với một JVM cụ thể, việc cấu hình nó một cách khác nhau có thể thay đổi chiến lược chính xác và phá vỡ phần mềm của bạn. Tóm lại, nó là một lỗi để dựa vào một chiến lược cụ thể.

Bộ nhớ cache của bạn quản lý loại tài nguyên nào? Nếu nó là một đối tượng phân bổ heap thuần túy, thì chiến lược sẽ không thành vấn đề. Việc sử dụng ReferenceQueue có thể giúp bạn thông báo khi SoftReference bị xóa.

Nếu loại tài nguyên không chỉ là đối tượng phân bổ heap, thì bạn phải yêu cầu người dùng gọi phương thức phát hành rõ ràng, tức là Closeable.close(). Để bảo vệ chống lại các cuộc gọi "quên" đối với phương thức phát hành này, bạn có thể xem xét việc thực hiện phương thức finalize(), nhưng hãy cẩn thận về các tác dụng phụ của nó. Để biết thêm thông tin về điều này, tôi khuyên bạn nên đọc "Mục 7: Tránh finalizers" từ "Hiệu quả Java (2nd Edition)" của Joshua Bloch.

+1

Tuy nhiên, đôi khi rất hữu ích khi hiểu cách JVM của bạn được triển khai và cách hoạt động của JVM. –

+0

Vâng, tất nhiên rồi. Chỉ cần không dựa vào nó. ;-) –

2

Tìm thấy một mẩu thông tin trong một FAQ HotSpot, có thể bị lỗi thời: http://www.oracle.com/technetwork/java/hotspotfaq-138619.html#gc_softrefs

Điều gì quyết định khi đối tượng nhẹ nhàng tham chiếu đang đỏ mặt?

Bắt đầu với 1.3.1, các đối tượng có thể truy cập nhẹ sẽ vẫn còn hoạt động trong một khoảng thời gian sau lần cuối cùng chúng được tham chiếu. Giá trị mặc định là một giây trong toàn bộ thời gian trên mỗi megabyte miễn phí trong heap. Giá trị này có thể được điều chỉnh bằng cờ -XX: SoftRefLRUPolicyMSPerMB, , chấp nhận giá trị nguyên thể hiện mili giây. Ví dụ, để thay đổi giá trị từ một giây đến 2,5 giây, sử dụng cờ này:

-XX: SoftRefLRUPolicyMSPerMB = 2500

Java HotSpot Server VM sử dụng kích thước heap tối đa có thể (như quy định với -Xmx tùy chọn) để tính toán không gian trống còn lại.

Máy khách Java Hotspot khách hàng sử dụng kích thước heap hiện tại để tính toán không gian trống .

Điều này có nghĩa là xu hướng chung là dành cho VM máy chủ để phát triển vùng heap hơn là tham chiếu mềm tuôn ra và -Xmx do đó có tác dụng đáng kể khi tham chiếu mềm là rác thu thập được.

Mặt khác, Máy khách sẽ có khuynh hướng tuôn ra tham chiếu mềm hơn là phát triển vùng heap.

Hành vi được mô tả ở trên là đúng cho 1.3.1 thông qua Java SE 6 phiên bản của máy ảo Java HotSpot. Tuy nhiên, hành vi này không phải là một phần của đặc tả VM và có thể thay đổi trong các bản phát hành trong tương lai. Tương tự cờ -XX: SoftRefLRUPolicyMSPerMB không được đảm bảo là có trong bất kỳ bản phát hành cụ thể nào.

Trước phiên bản 1.3.1, máy ảo Java HotSpot xóa tham chiếu mềm bất cứ khi nào tìm thấy chúng. chi tiết

Thậm chí nhiều hơn có sẵn tại địa chỉ: http://jeremymanson.blogspot.com/2009/07/how-hotspot-decides-to-clear_07.html (biếu không của bình luận MiserableVariable của)

0

Chỉ cần động não. Nếu bạn muốn bộ nhớ cache của mình bị xóa trước bộ nhớ cache khác, có thể bạn có thể liên kết cả hai? Có lẽ bằng cách giữ một tham chiếu mạnh mẽ đến các mục trong bộ nhớ cache thứ hai và chỉ phát hành các tài liệu tham khảo khi các thành viên của bộ nhớ cache của riêng bạn được xóa?

Có vẻ phức tạp. Tôi có lẽ sẽ nghiêng về phía chỉ đơn giản là chấp nhận rằng cả hai cache là chính xác đó, một bộ nhớ cache. Việc xóa bộ nhớ cache có thể gây khó khăn cho hiệu suất, nhưng ít nhất phần mềm của bạn sẽ không có chiến lược quản lý bộ nhớ cache phức tạp.

2

Không phải là điều này có thẩm quyền nhưng sử dụng SoftReference trong sự tức giận Tôi chưa bao giờ thấy VM xóa chúng thay vì tăng kích thước VM. Trên thực tế tôi bằng cách nào đó giả định rằng là trường hợp và thiết kế rất nhiều phụ thuộc vào đó. Tôi đã có cùng một số -ms-mx nhưng điều đó không quan trọng.

Nhưng tôi không thể tìm thấy bất kỳ thông số nào thực sự nói điều này là bắt buộc. This blog dường như đi sâu vào chi tiết cách thức SoftReferences bị xóa. Từ một đọc nhanh nó thực sự có vẻ như chúng có thể được xóa ngay cả khi bộ nhớ khác có sẵn.

+0

Tại sao downvote :( –

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