2015-01-06 3 views
4

Я хотел проверить функциональность Java WeakHashMap класса и по этому вопросу я написал следующий тест:Java WeakHashMap класс

public class WeakHashMapTest { 

public static void main(String args[]) { 
    Map<String, Object> weakMap = new WeakHashMap<>(); 
    String x = new String("x");  
    String x1 = new String("x1"); 
    String x2 = new String("x2"); 
    weakMap.put(x, x); 
    weakMap.put(x1, x1); 
    weakMap.put(x2, x2); 
    System.out.println("Map size :" + weakMap.size()); 
    // force all keys be eligible 
    x=x1=x2=null; 
    // call garbage collector 
    System.gc(); 
    try { 
     Thread.sleep(1000); 
    } catch (InterruptedException e) { 
     e.printStackTrace(); 
    } 

    System.out.println("Map size :" + weakMap.size()); 
    System.out.println("Map :" + weakMap); 
} 

}  

После запуска класса WeakMapTest я был неприятно удивлен, чтобы получить следующий вывод:

карта до gc: {x = x, x1 = x1, x2 = x2} карта после gc: {x = x, x1 = x1, x2 = x2}

, когда я ожидал, что карта будет пустой.

То есть сборщик мусора не выполнял свою работу. Но почему?

ответ

5

WeakHashMap будет иметь свои ключи, возвращенные сборщиком мусора, когда они больше не смогут достигать цели.

Реализация Примечание: Объектов значения в WeakHashMap проводится обычными сильными ссылками. Таким образом, следует проявлять осторожность, чтобы объекты ценности не сильно ссылались на свои собственные ключи, прямо или косвенно, поскольку это предотвратит отказ ключей.

Однако, поскольку вы использовали ключ как значение, значение все еще сильно достижимо, а это значит, что сборщик мусора не может вернуть ключи.

Однако, если вы используете другие объекты в качестве значений, то единственными ссылками на ключи будут сами ключи.

weakMap.put(x, new Object()); 
weakMap.put(x1, new Object()); 
weakMap.put(x2, new Object()); 

Затем, после очистки переменных и вызова сборщика мусора, как вы уже сделали, я получаю выход:

Map size :3 
Map size :0 
Map :{} 

Даже если вызов System.gc() не гарантирует сборщик мусора работает, похоже, что он работает здесь.

+0

Когда я использую код, который вы продемонстрировали выше, с новым Object(), он работает нормально, но что мне делать, когда я хочу что-то вроде Set implementation, когда ключ и значение имеют одну и ту же ссылку? –

+0

Я не знаю ни одного класса, поставляемого JDK, который бы обеспечил поведение 'WeakHashMap' для' Set'. – rgettman

+0

@IgalIsra Тогда вы, вероятно, захотите [Interner] Guava (http://docs.guava-libraries.googlecode.com/git/javadoc/com/google/common/collect/Interners.html#newWeakInterner()). – maaartinus

1

System.gc() является фактически предложение для запуска сборщика мусора. Нет никакого гарантированного пути к force сборщик мусора для запуска.

+0

[документация говорит иначе] (http://docs.oracle.com/javase/7/docs/api/java/lang/System.html#gc()): «Когда управление возвращается из вызова метода, виртуальная машина Java сделала все возможное, чтобы освободить место от всех отброшенных объектов ». – gknicker

+0

См., Например, http://stackoverflow.com/questions/66540/when-does-system-gc-do-anything, http://stackoverflow.com/questions/2414105/why-is-it-bad-practice-to-call- system-gc и несколько других источников. –

+0

Более конкретно, см. Http://bugs.java.com/view_bug.do?bug_id=6668279, что является ошибкой в ​​отношении документации. –