Философия Java

         

Хранение ссылок


Библиотека java.lang.ref содержит множество классов, которые придают большую гибкость сборщику мусора, что особенно полезно, когда у вас есть огромные объекты, могущие стать причиной нехватки памяти. Есть три класса, наследованные от абстрактного класса Reference: SoftReference, WeakReference и PhantomReference. Каждый из них обеспечивает различный уровень обхода для сборщика мусора, если только рассматриваемый объект достижим через один из этих объектов Reference.

Если объект достижим, это означает, что где-то в вашей программе этот объект может быть найден. Это может означать, что вы имеете обычную ссылку в стеке, которая указывает прямо не объект, но вы также можете иметь ссылку на объект, который имеет ссылку на рассматриваемый объект; здесь может быть много промежуточных связей. Если объект достижим, сборщик мусора не может освободить его, поскольку он все еще используется вашей программой. Если объект не достижим, для вашей программы нет способа использовать его, поэтому безопасно произвести сборку мусора за этим объектом.

Вы используете объекты Reference когда хотите продолжить хранить в ссылке такой объект — вы хотите быть способны достигнуть объекта — но вы также хотите позволить сборщику мусора освободить такой объект. Таким образом, вы имеете способ перейти к использованию объекта, но если память истощится, это грозит вам тем, что объект будет освобожден.

Вы выполните это, используя объект Reference, как промежуточную ступень между вами и обычной ссылкой, и при этом не должно быть обычных ссылок на объект (за исключением той, которая помещена внутрь объекта Reference). Если сборщик мусора обнаруживает, что объект достижим через обычную ссылку, он не освободит такой объект.

В порядке следования объектов SoftReference, WeakReference и PhantomReference, каждый из них “слабее” последнего и соответствует различному уровню достижимости. Мягкие (Soft) ссылки предназначены для реализации чувствительного к памяти кэширования. Слабые (Weak) ссылки предназначены для реализации “канонического преобразования” — когда экземпляры объектов могут быть одновременно использованы в разных местах программы, для сохранения хранилища — что не предотвращает ключи (или значения) от замены. Фантомные (Phantom) ссылки предназначены для назначения действий предсмертной очистки более гибким способом, чем это возможно с механизмом финализации.


Для SoftReference и WeakReference у вас есть выбор поместить ли их в ReferenceQueue (устройство, используемое для предсмертных действий по очистке), а PhantomReference могут быть построены только в ReferenceQueue. Вот пример простой демонстрации:

//: c09:References.java

// Демонстрация объектов Reference

import java.lang.ref.*;

class VeryBig { static final int SZ = 10000; double[] d = new double[SZ]; String ident; public VeryBig(String id) { ident = id; } public String toString() { return ident; } public void finalize() { System.out.println("Finalizing " + ident); } }

public class References { static ReferenceQueue rq= new ReferenceQueue(); public static void checkQueue() { Object inq = rq.poll(); if(inq != null) System.out.println("In queue: " + (VeryBig)((Reference)inq).get()); } public static void main(String[] args) { int size = 10; // или выберите размер через командную строку:

if(args.length > 0) size = Integer.parseInt(args[0]); SoftReference[] sa = new SoftReference[size]; for(int i = 0; i < sa.length; i++) { sa[i] = new SoftReference( new VeryBig("Soft " + i), rq); System.out.println("Just created: " + (VeryBig)sa[i].get()); checkQueue(); } WeakReference[] wa = new WeakReference[size]; for(int i = 0; i < wa.length; i++) { wa[i] = new WeakReference( new VeryBig("Weak " + i), rq); System.out.println("Just created: " + (VeryBig)wa[i].get()); checkQueue(); } SoftReference s = new SoftReference( new VeryBig("Soft")); WeakReference w = new WeakReference( new VeryBig("Weak")); System.gc(); PhantomReference[] pa = new PhantomReference[size]; for(int i = 0; i < pa.length; i++) { pa[i] = new PhantomReference( new VeryBig("Phantom " + i), rq); System.out.println("Just created: " + (VeryBig)pa[i].get()); checkQueue(); } } } ///:~

Когда вы запустите эту программу (вам нужно перенаправить вывод через утилиту “more”, так чтобы вы смогли просмотреть вывод по страницам), вы увидите, что объекты обработаны сборщиком мусора, даже если вы все еще имели доступ к ним через объекты Reference (для получения реальной ссылки, вы должны использовать get( )). Вы также увидите, что ReferenceQueue всегда производит Reference, содержащую null объект. Чтобы использовать его, вы можете наследовать от обычного класса Reference, который вас интересует и добавить больше полезных методов в новый тип Reference.


Содержание раздела