Когда Java WeakHashMap очистит нулевой ключ? - PullRequest
0 голосов
/ 02 марта 2019

В приведенном ниже коде nameRef.get() равно нулю, после name = null и System.gc().

import java.lang.ref.WeakReference;

public class Main {

    public static void main(String[] args) {
        String name = new String("ltt");

        WeakReference<String> nameRef = new WeakReference<>(name);    
        System.out.println(nameRef.get()); // ltt

        name = null;
        System.gc();

        System.out.println(nameRef.get());  // null
    }    
}

WeakHashMap основан на WeakReference.Наконец, я думаю, map.size() будет 0. На самом деле это 1.

import java.util.WeakHashMap;

public class Main2 {

    public static void main(String[] args) {
        String name = new String("ltt");
        WeakHashMap<String, Integer> map = new WeakHashMap<>();
        map.put(name, 18);
        System.out.println(map.size()); // 1

        name = null;
        System.gc();

        System.out.println(map.size());  // it's 1. why not 0 ?
    }    
}

Когда Java WeakHashMap очистит ключ null?

Ответы [ 4 ]

0 голосов
/ 04 апреля 2019

В вашем демо есть некоторые проблемы.На самом деле, размер 0 после System.gc () .В вашей ситуации это потому, что когда печать размера карты GC еще не закончена, то результат будет 1

0 голосов
/ 02 марта 2019

Простой ответ: вы не знаете.

Значение: у вас нет контроля, когда JVM запускает и запускает цикл GC.Вы не можете контролировать, когда подходящие объекты действительно собираются.

Таким образом, у вас нет возможности узнать, когда «состояние» этой карты изменяется.

И да, другая часть заключается в том, что вызов System.gc () является лишь рекомендацией для jvm по сбору мусора.В стандартной настройке у вас нулевой контроль, если jvm следует этому запросу или игнорирует его.Вам может понадобиться использовать очень специальные JVM, например, чтобы изменить это.

Как правило, gc запускается только тогда, когда jvm считает это необходимым.Таким образом, ваша карта может иметь размер 1, пока не будет недостатка памяти.И, как хорошо описывает ответ Хольгера, даже выполнение GC не заставляет карту обновлять эту часть.

0 голосов
/ 05 марта 2019

Как отмечают другие, нет гарантии, что System.gc() выполняет фактическую сборку мусора.Также не гарантирован цикл сбора мусора для фактического сбора определенного недоступного объекта.

Но в вашей конкретной настройке кажется, что System.gc() достаточно для сбора объекта, как определено вашим примером WeakReference.Но очистка слабой ссылки - это не то же самое, что очистка ссылки, чтобы позволить WeakHashMap выполнить ее очистку.Как объяснено в этом ответе , очистка WeakHashMap зависит от ключевой ссылки, которая будет поставлена ​​в очередь, которая будет проверяться каждый раз, когда вы вызываете метод для него, который является последующим map.size()Вызов в вашем примере.

Как и , документация WeakReference указывает:

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

Обратите внимание, как происходит очистка « в это время », тогда какпостановка в очередь произойдет « в то же время или в более позднее время ».

В случае HotSpot JVM / OpenJDK постановка в очередь происходит асинхронно после сборки мусора, и кажется, что ваш основной поток тоже работаетбыстро, поэтому ссылка на ключ еще не была поставлена ​​в очередь.

Вставка небольшой паузы может привести к успешному выполнению примера программы в типичных условиях:

import java.util.WeakHashMap;

public class Main2 {

    public static void main(String[] args) throws InterruptedException{
        String name = new String("ltt");
        WeakHashMap<String, Integer> map = new WeakHashMap<>();
        map.put(name, 18);
        System.out.println(map.size()); // 1

        name = null;
        System.gc();

        Thread.sleep(10);

        System.out.println(map.size()); // 0
    }    
}

Конечно, это не изменитсятот факт, что это удобно для тестирования, но не гарантирует гарантированного поведения, поэтому не следует писать производственный код, опираясь на него.

0 голосов
/ 02 марта 2019

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

См. Документацию :

[...] Вызов ** * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Т. Е. , что означает, что виртуальная машина Java затрачивает усилия на утилизацию неиспользуемых объектов, чтобы сделать доступной память в настоящее время доступной для быстрого повторного использования. Когда элемент управления возвращает из вызова метода, виртуальная машина Java приложила все усилия для освобождения пространства от всех отброшенных объектов.[...]

Сказав это, вы не сможете узнать, когда исчезла запись на карте, кроме как регулярно проверять ее.

...