2009-05-21 26 views

Trả lời

1

Bằng cách gọi System.gc() bộ thu gom rác được chạy, như tên gọi. Tại thời điểm này, khi các đối tượng đang thực sự được gỡ bỏ, các finalize() được gọi trên các đối tượng này trước khi chúng biến mất.

Câu hỏi cuối cùng không được có "or" trong đó. Đó là bộ sưu tập rác giảm hiệu suất.

Thông thường, bạn không nên quan tâm đến gc vì nó thực sự là một công việc tốt cho bạn. Có các tình huống sử dụng mà bạn muốn loại bỏ rất nhiều đối tượng tại một thời điểm nhất định; Sau đó, nó là khả thi.

+13

System.gc() không nhất thiết gọi GC. Nó chỉ là một gợi ý cho JVM rằng đây là thời điểm thích hợp để chạy GC, nhưng quyết định cuối cùng để chạy nó là tùy thuộc vào JVM. – coobird

+0

Tôi hy vọng thời gian mà gc không chạy nếu bạn gọi System.gc() khá thấp. Mặt khác, gc chỉ chạy hoàn toàn nếu đạt đến ngưỡng. Bằng cách gọi gc() bạn thường chỉ cần gc trước. –

+1

Với một CPU đơn, nếu bạn System.gc() và có rất nhiều thứ để dọn dẹp, bạn có thể thấy một vách đá thực sự thực sự cho đến khi dọn dẹp xong. Điều này có thể thực sự đau đớn nếu bạn chạy gần với trần bộ nhớ của nhiệm vụ JVM của bạn và nó tự động thực hiện GC nghiêm trọng trên chính nó. Nhưng nếu bạn có nhiều CPU, các vấn đề về hiệu suất sẽ ít hơn rất nhiều vì GC có thể xảy ra trên CPU khác và phần còn lại của JVM của bạn rất vui nhộn ... – jlarson

8

Chính xác điều gì xảy ra khi bạn gọi System.gc() là tùy thuộc vào JVM. JVM xem cuộc gọi này là một đề xuất rằng đây có thể là thời điểm thích hợp để chạy bộ thu gom rác, do đó, không phụ thuộc vào nó.

Phương thức finalize() của đối tượng được chạy trên đối tượng bởi bộ thu gom rác khi JVM xác định rằng không có tham chiếu có thể truy cập nhiều hơn đến đối tượng đó. Bạn không nên gọi nó trong mã của bạn. Lưu ý rằng finalize() là không phải được gọi vào thời điểm chương trình của bạn mất tham chiếu cuối cùng, nhưng vào thời điểm trong tương lai khi trình thu gom rác chạy, do đó, không phụ thuộc vào nó xảy ra tại một thời điểm cụ thể (hoặc ở tất cả).

0

finalize() là phương tiện để thực thi bit cuối cùng của mã ngay trước khi đối tượng sẵn sàng thu gom rác (khi đối tượng không có tham chiếu mạnh mẽ đến nó).

Vậy khi nào nó nên được sử dụng? Chỉ trong hai trường hợp hiện tại:

  1. Là một an toàn để đảm bảo rằng một số dịch vụ được đóng cửa hoặc một số mong muốn thay đổi cuối cùng được thực hiện. Ví dụ, lớp InputStream sử dụng nó để đóng luồng i/o. Đó là ví dụ bạn đã tạo một thể hiện của BufferedInputStream. Thủ công sau khi sử dụng nó là giả sử đóng() nó. Nhưng bởi vì người ta có thể quên làm điều đó, finalize() hoạt động như một mạng lưới an toàn để đóng() luồng.
  2. Trong khi sử dụng Native’s. Vì bộ thu gom rác không có quyền kiểm soát đối tượng gốc, kết thúc() có thể được sử dụng như một phương tiện để đòi lại nó.

Ngoài hai trường hợp trên không bao giờ sử dụng. Để hiểu tại sao? chúng ta cần hiểu chức năng và vòng đời của một vật thể.

Giới thiệu: Có một chuỗi daemon riêng biệt được gọi là chuỗi trình hoàn thiện chịu trách nhiệm gọi phương thức finalize(). Hàng đợi cuối cùng là hàng đợi nơi các đối tượng sẵn sàng gọi là phương thức finalize() được đặt.

  1. Khi đối tượng được tạo, JVM sẽ kiểm tra xem đối tượng có phương thức finalize() hay không. Nếu nó có thì nó nội bộ lưu ý rằng đối tượng cụ thể này có phương thức finalize().

Khi một đối tượng đã sẵn sàng cho thu gom rác thải, sau đó thu gom rác chủ đề kiểm tra nếu đối tượng đặc biệt này có hoàn thiện() từ bảng nêu ở mục (1).

  • 2a) Nếu không thì nó sẽ được gửi cho thu gom rác thải.

    2b) Nó có, sau đó nó được thêm vào hàng đợi cuối cùng. Và nó loại bỏ mục nhập của đối tượng khỏi bảng (1).

Chuỗi kết thúc tiếp tục bỏ phiếu. Đối với mỗi đối tượng trong hàng đợi, phương thức finalize() của nó được gọi. Sau khi gọi vòng lặp finalize() từ (2) một lần nữa được lặp lại. Nếu đối tượng này vẫn không có tham chiếu mạnh, thì gửi cho GC. Nếu nó đã sau đó LUÔN (2a) được gọi vì mục đã bị xóa trong (2b)

Basically finalize() method is only called once. 

Vậy điều gì là vấn đề với chu kỳ trên?

Từ (1). Mất thêm thời gian để tạo đối tượng. Phân bổ bộ nhớ trong Java là 5x đến 10x nhanh hơn so với malloc/calloc vv. Tất cả thời gian thu được bị mất trong thủ tục ghi chú đối tượng trong bảng vv. Tôi đã từng thử nó. Tạo 100000 đối tượng trong một vòng lặp và đo thời gian thực hiện cho chương trình để chấm dứt trong 2 trường hợp: Một không có kết thúc(), Thứ hai với hoàn thành(). Tìm thấy nó nhanh hơn 20%.

Từ (2b): Rò rỉ bộ nhớ và đói. Nếu đối tượng trong hàng đợi có tham chiếu đến nhiều tài nguyên bộ nhớ, thì tất cả các đối tượng đó sẽ không được giải phóng trừ khi đối tượng này sẵn sàng cho GC.If tất cả các đối tượng là đối tượng có trọng lượng nặng, thì có thể thiếu.

Từ (2b): Vì finalize() chỉ được gọi một lần, nên nếu kết thúc() bạn có tham chiếu mạnh mẽ đến đối tượng “this”. Lần sau, finalie() không bao giờ được gọi là do đó có thể rời khỏi đối tượng trong trạng thái không nhất quán.

Nếu bên trong hoàn thành() một ngoại lệ được ném, nó sẽ bị bỏ qua.

Bạn không biết khi nào finalize() được gọi là bạn không kiểm soát được khi GC được gọi. Đôi khi nó có thể xảy ra mà bạn đang in giá trị trong finalize() nhưng đầu ra không bao giờ được hiển thị, bởi vì chương trình của bạn có thể đã bị chấm dứt bởi thời gian finalize() được gọi.

Do đó, tránh sử dụng nó. Thay vào đó, hãy tạo một phương thức nói vứt bỏ() sẽ đóng tài nguyên cần thiết hoặc cho nhật ký cuối cùng, v.v. the complete post on it. Tôi hy vọng điều này rõ ràng.

+0

Stack Overflow thích rằng bạn cung cấp nội dung trong câu trả lời của bạn, không chỉ là một liên kết. Nếu liên kết phá vỡ câu trả lời của bạn sẽ không có giá trị. –

+1

Xong !! Cảm ơn đề xuất – Jatin

0

System.gc() dọn dẹp bộ nhớ và sử dụng finalize() để loại bỏ các đối tượng riêng lẻ.

0

Có System.gc(); sẽ kích hoạt phương thức finalize() nếu được yêu cầu. public class TestGarbageCollection {

public static void main(String[] args) { 
    while (true) { 
     TestClass s = new TestClass(); 
     s.display(); 
     System.gc(); 
    } 
} 

}

public class TestClass {

public TestClass() { 
    System.out.println("constructor"); 
} 

public void display() { 
    System.out.println("display"); 
} 
@Override 
public void finalize() { 
    System.out.println("destructor"); 
} 

}

này sẽ kích hoạt phương pháp hoàn thiện(). cho dù bạn override finalize hoặc không hoàn thành phương thức của lớp địa phương hoặc Object's finalize sẽ được gọi.

+0

Không đúng !! Của nó khi JVM cho dù phương pháp hoàn thành nên được gọi là trong quá trình thu gom rác hay không. Và cũng như theo Java-doc, gọi 'System.gc' không đảm bảo rằng nó ngay lập tức gọi cho Garbage Collector for Memory free-up. Chỉ là gợi ý của nó !!! –

+0

@Arun Kumar: Mặc dù Oracle System.gc() JavaDocs nói: "Gọi phương thức này cho thấy rằng Java Virtual Machine nỗ lực hết sức để chạy các phương thức hoàn thiện của các đối tượng đã được tìm thấy sẽ bị loại bỏ, nhưng phương thức hoàn thiện của chúng chưa được chạy. ** 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 để hoàn thành tất cả các quyết toán chưa xử lý. ** "Câu cuối cùng là rất rõ ràng. Và câu đúng trước khi nó thấm nước. Tôi ước họ sẽ sửa những tài liệu đó, bởi vì bây giờ tôi không biết phải nghĩ gì. –

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