2011-01-24 70 views
14

Người ta nói rằng chúng tôi không thể bắt buộc quy trình garbage collection trong java.
Sau tất cả, một chuỗi daemon.Gọi điện System.gc() một cách rõ ràng?

Nhưng đôi khi, tại sao chúng tôi gọi hàm System.gc(); một cách rõ ràng?
Có đáng gọi không? Bất kỳ Pro và Con của?
Nếu không hữu ích trong nhiều trường hợp, tại sao phương pháp này không được dùng nữa từ Java?

PS: Giải thích với một ví dụ sẽ hữu ích

Trả lời

8

Cách tốt nhất, theo ý kiến ​​của tôi, để nghĩ về phương pháp System.gc() là một "gợi ý" cho máy ảo mà bộ sưu tập rác sẽ chạy. Điều đó nói rằng, giống như một tỷ lệ phần trăm lớn của "tối ưu hóa" mọi người nghĩ rằng họ đang thực hiện, nó thường là tốt nhất để chỉ cho hệ thống tự chăm sóc mọi thứ. Các hệ thống đang phát triển vv .. v.v. Vẫn còn một số trường hợp nhà phát triển có thể thực sự biết rõ hơn và trường hợp sử dụng cho nó có lẽ rất giống với lý do tại sao một số mã vẫn được viết trong assembly (phần lớn thời gian, trình biên dịch là tốt hơn , nhưng trong một vài trường hợp - hoặc với một vài nhà phát triển - con người thực sự có thể viết mã hiệu quả hơn).

Một ví dụ tôi đã thấy trong quá khứ để biện minh cho sự tồn tại của nó trong trường hợp một số lượng lớn các đối tượng được phân bổ và bạn là nhà phát triển biết ngay lập tức chúng không còn được sử dụng nữa. Trong trường hợp đó, bạn có thể có thêm thông tin về việc sử dụng bộ nhớ so với GC (hoặc ít nhất, trước khi nó nhận ra nó) và, vì số lượng bộ nhớ khai hoang sẽ là đáng kể, nên có nghĩa là nó chạy.

6

Q: tại sao chúng ta gọi là System.gc(); chức năng một cách rõ ràng?

A: Vì ai đó đã viết mã xấu.

Tôi nghĩ hầu hết mọi người đều đồng ý rằng bạn không nên gọi System.gc() một cách rõ ràng.

Để hệ thống quản lý bộ nhớ như được cho là. Bất kỳ mã nào dựa vào đó cho hiệu suất có nhiều khả năng bị hỏng. Ngoài ra, hãy nhớ rằng JVM hoàn toàn có thể bỏ qua yêu cầu của bạn.

Nếu bạn muốn biết thêm thông tin, tôi muốn khuyên bạn nên đọc câu trả lời cho:

java - why is it a bad practice to call System.gc?

+0

Có. Đó là những gì HFJ gợi ý. Nhưng không thực sự thuyết phục về câu trả lời của họ. –

8

Bạn đã trả lời một nửa số câu hỏi của bạn: nó có giá trị nó? Không, bởi vì bạn không thể ép buộc nó.

Chạy bộ thu gom rác. Việc gọi phương thức này cho thấy rằng máy ảo Java tốn nhiều nỗ lực để tái chế các đối tượng không sử dụng để tạo ra bộ nhớ mà chúng hiện đang có sẵn để tái sử dụng nhanh chóng.

Đây gần như EULA-tiếng Anh cho "bạn có thể thử nhưng cả hai chúng tôi đều biết kết quả". :)

Hơn nữa, máy chủ ứng dụng có thể (và thường sẽ) vô hiệu hóa tính năng này bằng cách sử dụng tùy chọn dòng lệnh -XX:-DisableExplicitGC.

Vậy thì vấn đề là gì? Vâng, có thể có một: một số ứng dụng như để hiển thị số lượng bộ nhớ trống có sẵn trên heap, và trước khi bạn làm mới màn hình của bạn, nó có thể là vừa phải hữu ích để gọi System.gc(); trước khi nó.

+0

System.gc() là một cuộc gọi khá đắt tiền. "Khi điều khiển trả về từ cuộc gọi phương thức, Máy ảo Java đã thực hiện một nỗ lực tốt nhất để lấy lại không gian từ tất cả các đối tượng bị loại bỏ". – RecursiveExceptionException

+1

Điều này giống như nói rằng lối sống lành mạnh không đáng giá vì nó không được đảm bảo để hoạt động. Nếu bạn kiểm soát môi trường, bạn có thể đảm bảo rằng nó hoạt động. Có nhiều sự lạm dụng hơn việc sử dụng 'System.gc()' đúng cách, nhưng điều này không làm cho nó vô ích. – maaartinus

0

Phiên bản Java nào chúng ta đang nói đến ở đây? Trong 6, tôi sẽ không bao giờ gọi nó một cách rõ ràng. Như một quy tắc chung của ngón tay cái thu gom rác là đủ tốt để biết khi nào tốt nhất để làm sạch tài nguyên và nó có đủ tùy chọn VM cấu hình. Tôi đã chắc chắn không bao giờ cảm thấy cần phải gọi nó trong mã, và tôi muốn nói, trừ khi bạn đã làm một cái gì đó thực sự kỳ lạ (hoặc hiển thị sử dụng tài nguyên) tốt nhất là không. Nếu bạn cảm thấy cần phải gọi nó thì tôi nói bạn đã làm điều gì đó xấu hoặc sai ở đâu đó.

Nếu chúng ta đang nói về làm việc với Java 1.4 hoặc trước đó, đôi khi tôi thấy nó cần một bàn tay giúp đỡ. Không có ví dụ để tay (xin lỗi) nhưng tôi nhớ cần phải ném nó một gợi ý để tránh tụt hậu khủng khiếp khi nó quyết định cuối cùng đá vào. Với mã tương tự trên 6, vấn đề đã biến mất và gọi nó làm ít hoặc không có sự khác biệt.

Tất nhiên, khi bạn đang gọi System.gc() tất cả những gì bạn đang thực hiện đang đề xuất với máy ảo, đây có thể là thời điểm tốt để chạy bộ thu gom rác. Nó không có nghĩa là nó thực sự sẽ, nó chỉ đơn thuần là một gợi ý rằng việc thực thi VM hoàn toàn hợp lệ hoàn toàn có thể bỏ qua. Trong thực tế thậm chí có một tùy chọn DisableExplicitGC có nghĩa là các cuộc gọi chắc chắn sẽ không có ảnh hưởng (và nhiều mã trong môi trường sản xuất được chạy với tùy chọn này.)

Vì vậy, nó vẫn được sử dụng trong mã - nhưng phần lớn thời gian nó không phải là thực hành tốt cả.

3

Có một số trường hợp khi gọi System.gc() rất hữu ích:

  • Bạn sẽ chạy một số điểm chuẩn, vì vậy bạn cần phải bắt đầu trong trạng thái được xác định rõ.
  • Bạn đang mong đợi một số tải nặng và muốn chuẩn bị tốt nhất có thể.
  • Bạn có nhiều máy chủ và muốn tránh tạm dừng bằng cách lên lịch GC theo định kỳ like here.

Có thể có nhiều trường hợp sử dụng hơn, tuy nhiên, không có gì bạn có thể mong đợi cần sớm. Hầu hết thời gian nó tốt hơn để cho nó làm công việc của nó theo cách của nó.

+1

Tôi không đồng ý với điều thứ hai - nếu bạn bắt đầu chạy một tải "nặng" thì nói chung JVM là đủ tốt để nhận ra điều này và sẽ GC khi thích hợp. – berry120

+0

Ý tôi là, bạn làm điều đó * trước * bạn bắt đầu tải nặng, đó là điều mà JVM không thể biết trước. Nó giống như làm tất cả các nhiệm vụ trước khi bạn mong đợi một ngày khó khăn để đến. – maaartinus

+0

@ berry120 bạn có thể làm trống gen trẻ (trên hotspot của Sun) nếu bạn chắc chắn bạn sẽ bung nó. Nói chung, gọi GC trong môi trường đa luồng không được khuyến nghị bằng bất kỳ cách nào ngoại trừ việc khắc phục các vấn đề mà các nhà phát triển java biết ơn. (nói một lần nữa về bộ đệm được ánh xạ bộ nhớ) – bestsss

-1
It is said that we cannot force the garbage collection process in java. 

Đó là một niềm tin rất phổ biến, điều đó hoàn toàn sai.

Một số ứng dụng thực hiện điều đó một cách thường xuyên và một số thậm chí có các nút sáng bóng mà bạn có thể nhấp vào thực hiện thực sự thực hiện một GC. Nói cách khác: họ không "gợi ý" GC mà họ muốn GC kích hoạt nhưng chúng thực sự buộc một GC.

Vì vậy, niềm tin đó vừa phổ biến vừa sai. Thế nào là ít phổ biến là những kiến ​​thức như thế nào bạn thực sự kích hoạt một GC như vậy, như thể hiện bởi câu trả lời duy nhất (và rất mơ hồ) để tôi 6 lần câu hỏi upvoted ở đây:

Java: How do you really force a GC using JVMTI's ForceGargabeCollection?

+5

Bạn không thể "ép buộc" một JVM chung để thực hiện thu gom rác vì một bộ thu gom rác không thực sự được yêu cầu bởi đặc tả JVM. – ILMTitan

+1

"Khi điều khiển trả về từ cuộc gọi phương thức, Máy ảo Java ** đã thực hiện một nỗ lực tốt nhất để lấy lại không gian ** từ tất cả các đối tượng bị loại bỏ." Không có lý do cho một cuộc bỏ phiếu xuống, một JVM thiếu GC nỗ lực tốt nhất của nó, quá. – maaartinus

+0

@ILMTitan: Sau đó, tôi đoán đó là một điều tốt cho 99% chương trình Java đang chạy trên các máy ảo cho phép thiết bị jvmti và do đó hỗ trợ cuộc gọi được ghi lại;) – SyntaxT3rr0r

2

Không có ý định trả lời các câu hỏi, gọi thu gom rác một cách rõ ràng là một thực tế xấu, xấu, tuy nhiên một số mã trong java không dựa vào quyết toán ... và cố gắng để thực thi nó. Gọi nó là hữu ích trong một số kịch bản profiling là tốt. Không có JVM chuẩn nào bỏ qua System.gc(). Chắc chắn, nó có thể bị vô hiệu hóa.Tuy nhiên, b/c sang một bên bộ nhớ, bộ thu gom rác sẽ quản lý các tham chiếu java tới các tài nguyên bên ngoài, nó có thể là cần thiết.

đây là một số mã từ java.nio.Bits

static void reserveMemory(long size) { 

    synchronized (Bits.class) { 
     if (!memoryLimitSet && VM.isBooted()) { 
      maxMemory = VM.maxDirectMemory(); 
      memoryLimitSet = true; 
     } 
     if (size <= maxMemory - reservedMemory) { 
      reservedMemory += size; 
      return; 
     } 
    } 

    System.gc(); 
    try { 
     Thread.sleep(100); 
    } catch (InterruptedException x) { 
     // Restore interrupt status 
     Thread.currentThread().interrupt(); 
    } 
    synchronized (Bits.class) { 
     if (reservedMemory + size > maxMemory) 
      throw new OutOfMemoryError("Direct buffer memory"); 
     reservedMemory += size; 
    } 

Ngủ là cần thiết cho việc quyết toán mới để chạy thực sự (hoặc chạy thử), chất tẩy rửa thường có fast-track trên thread finalizer ưu tiên cao.

0

Đó là một anti-pattern to use System.gc() rõ ràng, mặc dù chúng tôi sử dụng nó để đề xuất JVM để quét rác nhưng nó là tùy thuộc vào JVM cho dù nó có hay không, nó tiếp tục áp đặt một số tiêu chí mà nó nhìn vào khi xảy ra System.gc(). Nếu tiêu chí sau đó nó hành động; nếu không thì không.

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