2015-11-02 20 views

Trả lời

6

Bạn có thể làm theo này blog:

tốt là gì PhantomReferences? Tôi chỉ biết hai trường hợp nghiêm trọng đối với họ: đầu tiên, chúng cho phép bạn xác định chính xác khi một đối tượng bị xóa khỏi bộ nhớ. Trên thực tế, đó là cách duy nhất để xác định điều đó. Điều này thường không hữu ích, nhưng có thể có ích trong các trường hợp cụ thể như thao tác hình ảnh lớn: nếu bạn biết chắc chắn rằng một hình ảnh phải được thu gom rác, bạn có thể đợi cho đến khi nó thực sự trước khi cố gắng tải hình ảnh tiếp theo, và do đó làm cho OutOfMemoryError sợ hãi ít có khả năng xảy ra.

Thứ hai, PhantomReferences tránh một vấn đề cơ bản với hoàn thiện: phương thức finalize() có thể "hồi sinh" các đối tượng bằng cách tạo các tham chiếu mới mạnh mẽ cho chúng. Vì vậy, những gì, bạn nói? Vâng, vấn đề là rằng một đối tượng ghi đè hoàn chỉnh() bây giờ phải được xác định là rác trong ít nhất hai chu kỳ thu gom rác riêng biệt để thu thập . Khi chu kỳ đầu tiên xác định rằng đó là rác, nó trở nên đủ điều kiện để hoàn thành. Bởi vì khả năng (mỏng, nhưng không may thực) mà đối tượng đã "phục sinh" trong quá trình hoàn thiện, trình thu gom rác phải chạy lại trước khi đối tượng thực sự có thể bị xóa. Và bởi vì hoàn thành có thể không đã xảy ra một cách kịp thời, một số lượng tùy ý của rác chu kỳ thu thập có thể đã xảy ra trong khi đối tượng đang chờ kết quả thanh toán . Điều này có thể có nghĩa là sự chậm trễ nghiêm trọng trong thực tế làm sạch các đối tượng rác , và là lý do tại sao bạn có thể nhận được OutOfMemoryErrors ngay cả khi hầu hết các đống rác.

Cũng đọc: The Mysterious Phantom Reference

Xét đoạn mã sau.

public class Foo { 

    private String bar; 

    public Foo(String bar) { 
     this.bar = bar; 
    } 

    public String foo() { 
     return bar; 
    } 
} 

Vì vậy, cho phép nói sau khi đối tượng đã được hoàn toàn dereferenced bởi ứng dụng Tôi muốn một số cách gọi foo(). Đây là một số mã mà tôi dự kiến ​​sẽ hoạt động mà sẽ làm điều này với một niggle.

// initialize 
ReferenceQueue<Foo> queue = new ReferenceQueue<Foo>(); 
ArrayList< PhantomReference<Foo>> list=new ArrayList<PhantomReference<Foo>>(); 

for (int i = 0; i < 10; i++) { 
    Foo o = new Foo(Integer.toOctalString(i)); 
    list.add(new PhantomReference<Foo>(o, queue)); 
} 

// make sure the garbage collector does it’s magic 
System.gc(); 

// lets see what we’ve got 
Reference<? extends Foo> referenceFromQueue; 
for (PhantomReference<Foo> reference : list) 
    System.out.println(reference.isEnqueued()); 

while ((referenceFromQueue = queue.poll()) != null) { 
    System.out.println(referenceFromQueue.get()); 
    referenceFromQueue.clear(); 
} 

PhantomReference có phiên bản Foo và ReferenceQueue. Kể từ không có tay cầm nào được giữ cho Foo, nó sẽ ngay lập tức bị chết. Tiếp theo, yêu cầu máy ảo thu thập vì không đủ số lượng để máy ảo kích hoạt bộ sưu tập một cách tự nhiên. Điều đầu tiên tôi sẽ yêu cầu PhantomReference là; bạn đã được enqueued. Trong trường hợp này, câu trả lời sẽ là đúng. Tiếp theo, tôi yêu cầu hàng đợi tham chiếu nhưng khi bạn có thể thấy, gọi get() luôn trả về giá trị rỗng. Về giải pháp duy nhất mà có ý nghĩa là bao bọc các tài nguyên hoặc đối tượng bạn muốn tương tác với trong một phân lớp của PhantomReference.

public class FinalizeStuff<Foo> extends PhantomReference<Foo> { 

    public FinalizeStuff(Foo foo, ReferenceQueue<? super Foo> queue) { 
     super(foo, queue); 
    } 

    public void bar() { 
     System.out.println("foobar is finalizing resources"); 
    } 
} 

Trong trường hợp này tôi sẽ không để quấn Foo trong lớp con như rằng sẽ dường như vi phạm tinh thần của PhantomReference. Thay vào đó, tôi sẽ truy cập vào tài nguyên được liên kết với Foo và tương tác với chúng. Bây giờ tôi có thể làm điều này.

// initialize 
ReferenceQueue<Foo> queue = new ReferenceQueue<Foo>(); 
ArrayList< FinalizeStuff<Foo>> list = new ArrayList<FinalizeStuff<Foo>>(); 
ArrayList<Foo> foobar = new ArrayList<Foo>(); 

for (int i = 0; i < 10; i++) { 
    Foo o = new Foo(Integer.toOctalString(i)); 
    foobar.add(o); 
    list.add(new FinalizeStuff<Foo>(o, queue)); 
} 

// release all references to Foo and make sure the garbage collector does it’s magic 
foobar = null; 
System.gc(); 

// should be enqueued 
Reference<? extends Foo> referenceFromQueue; 
for (PhantomReference<Foo> reference : list) { 
    System.out.println(reference.isEnqueued()); 
} 

// now we can call bar to do what ever it is we need done 
while ((referenceFromQueue = queue.poll()) != null) { 
    ((FinalizeStuff)referenceFromQueue).bar(); 
    referenceFromQueue.clear(); 
} 
Các vấn đề liên quan