Утечки памяти в Java 1.6: HashMap и ArrayList - PullRequest
0 голосов
/ 03 декабря 2011

Edit: Нет утечки памяти, просто недоразумение, что мне говорит Netbeans Profiler. Результаты прямого профилирования -> Выделенные объекты относятся к ОБЩЕМУ, выделенному за время существования программы, а не к общему количеству, которое в настоящее время находится в памяти. За это получите кучу дампов. Извините за путаницу, но, возможно, кто-то еще найдет это, и это прояснит это для них.


Я использую профилировщик NetBeans 7.0.1 для устранения проблем с ростом памяти в моем приложении и вижу две основные проблемы. Я успешно создал тестовые приложения и вижу те же результаты в профилировщике, включенном ниже. Я не смог найти ссылку на них где-либо еще.

Случай 1: при циклическом просмотре набора записей HashMap объект java.util.HashMap & EntryIterator увеличивается. Есть ли здесь что-нибудь, кроме как найти решение с другим контейнером? Каждому приложению необходим циклический просмотр коллекции каждый раз в цикле while.

public static void main(String[] args) throws InterruptedException {
    boolean run = true;
    HashMap<Integer, Integer> map = new HashMap<Integer, Integer> ();
    map.put(1, 2);map.put(3, 4);map.put(5, 6);map.put(7, 8);
    while(true){
        for (Entry<Integer, Integer> entry : map.entrySet()) {
        Integer i = entry.getValue();
        }

        //app specific code here

        Thread.sleep(50);
    }
}

Случай 2. Создание пустых списков ArrayLists в цикле приводит к росту java.lang.Object []. Я ожидаю, что ArrayLists будет иметь право на GC в конце цикла while. Мое предположение неверно? Или здесь что-то еще играет?

public static void main(String[] args) throws InterruptedException {
    boolean run = true;
    while(run){
        ArrayList<Integer> a1 = new ArrayList<Integer>();
        ArrayList<Integer> a2 = new ArrayList<Integer>();

        // app specific code here

        Thread.sleep(50);
    }
}

Ответы [ 6 ]

2 голосов
/ 03 декабря 2011

Я не думаю, что ни один из примеров кода пропускает память.Вы должны обязательно различать «куча растет до тех пор, пока сборщик мусора не запускается» и «куча растет вечно».Если вы удалите вызовы Thread.sleep и запустите какое-либо приложение навсегда, это не должно привести к сбою, и использование кучи JVM должно расти и падать по мере работы сборщика мусора.Вы можете попробовать запустить «System.gc ()» во время каждого цикла и проверить, не обнаружена ли утечка в вашем профилировщике.

0 голосов
/ 03 октября 2013

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

С уважением, Лалита

0 голосов
/ 03 декабря 2011

Многое из того, что вы говорите, зависит от таких строк, как:

// app specific code here

То, что вы здесь делаете, может сильно повлиять на сборку мусора. Для кода, который вы разместили, это приведет к утечке памяти. Например, каждый раз через этот цикл:

public static void main(String[] args) throws InterruptedException {
    boolean run = true;
    while(run){
        ArrayList<Integer> a1 = new ArrayList<Integer>();
        ArrayList<Integer> a2 = new ArrayList<Integer>();

        // app specific code here

        Thread.sleep(50);
    }
}

выделенные объекты становятся доступными для сборки мусора. Память может продолжать расти, пока не достигнет своего выделенного предела, но после этого объекты будут собираться мусором.

Запустите ваш код вне netbeans и запустите на нем jvisualvm . Посмотрите, что на самом деле происходит.

0 голосов
/ 03 декабря 2011

Хотя я не могу найти ничего тревожного, я только что попробовал оба ваших фрагмента кода.Я удалил sleep s, чтобы ускорить тестирование.Сборщик мусора работает как сумасшедший несколько раз в секунду и по сути очищает все молодое поколение (попробуйте с -XX:+PrintGCDetails -XX:+PrintGCTimeStamps):

[GC [PSYoungGen: 104272K->0K(99712K)] 105235K->963K(131968K), 0.0008090 secs] [Times: user=0.01 sys=0.00, real=0.00 secs]

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

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

0 голосов
/ 03 декабря 2011

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

Даже если ваши объекты были инициализированы вне цикла, тогда и на некоторых компиляторах байт-код был бы таким же, как они былисозданный внутри цикла, разница невелика.

Более того, вы не можете гарантировать, что GC когда-либо будет работать и ваши объекты будут возвращены.

РЕДАКТИРОВАТЬ:

Подобный пост на SO

0 голосов
/ 03 декабря 2011

Ваши ArrayLists во втором примере будут иметь право на GC, если нет другого кода, который ссылается на них.Кроме того, вы не можете контролировать, как и когда выполняется сборка мусора.Вы знаете, какой сборщик мусора вы используете?Вы запускаете свою программу с какими-либо конкретными флагами vm?Испытываете ли вы странное поведение после вызова System.gc для принудительного сбора мусора?Код вашего приложения ссылается на списки массивов?

...