it-swarm-ru.tech

Может ли быть утечка памяти в Java

Я получил этот вопрос много раз. Какой хороший способ ответить

33
javaguy

Может ли быть утечка памяти в Java?

Ответ в том, что это зависит от того, о какой утечке памяти вы говорите.

Классические утечки памяти в C/C++ происходят, когда приложение игнорирует free или dispose объект, когда они закончили с ним, и оно протекает. Циклические ссылки являются частным случаем этого, когда приложение испытывает затруднения, зная, когда freedispose, и в результате этого пренебрегает. Схожие проблемы связаны с тем, что приложение использует объект после его освобождения или пытается дважды его освободить. (Вы можете назвать последние проблемы утечками памяти или просто ошибками. В любом случае ...)

Java и другие (полностью1) управляемые языки _/в основном не страдают от этих проблем, потому что GC заботится об освобождении объектов, которые более недоступны. (Конечно, проблем с висящим указателем и отсутствием двойного освобождения не существует, и циклы не являются проблематичными, как для «умных указателей» C/C++ и других схем подсчета ссылок.)

Но в некоторых случаях GC в Java будет пропускать объекты, которые (с точки зрения программиста) следует собирать мусором. Это происходит, когда GC не может понять, что объект не может быть достигнут:

  • Логика/состояние программы может быть таким, что пути выполнения, которые будут использовать некоторую переменную, не могут возникать. Разработчик может видеть это как очевидное, но GC не может быть уверен, и ошибается в сторону осторожности (как это требуется).
  • Программист может ошибаться, и сборщик мусора избегает того, что в противном случае может привести к зависанию.

(Обратите внимание, что причины утечек памяти в Java могут быть простыми или довольно тонкими; см. Ответ @ jonathan.cone для некоторых тонких. Последний может включать внешние ресурсы, на которые вы не должны полагаться на GC, чтобы разберись в любом случае.)

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

Тогда возникает проблема, заключающаяся в том, что приложение или библиотека Java могут выделять объекты вне кучи через собственный код, которым необходимо управлять вручную. Если приложение/библиотека содержит ошибки или используется неправильно, вы можете получить утечку памяти. (Например: утечка памяти Android Bitmap ... отмечая, что эта проблема исправлена ​​в более поздних версиях Android.)


1 - Я имею в виду пару вещей. Некоторые управляемые языки позволяют писать неуправляемый код, где вы можете создавать классические утечки памяти. Некоторые другие управляемые языки (или, точнее, языковые реализации) используют подсчет ссылок, а не надлежащий сборщик мусора. Менеджеру хранилища на основе подсчета ссылок необходимо что-то (например, приложение), чтобы прервать циклы ... иначе произойдет утечка памяти.

21
Stephen C

Что ж, учитывая, что Java использует сборщик мусора для сбора неиспользуемых объектов, вы не можете иметь висячий указатель. Однако вы можете держать объект в области действия дольше, чем нужно, что можно считать утечкой памяти. Подробнее об этом здесь: http://web.archive.org/web/20120722095536/http://www.ibm.com:80/developerworks/rational/library/05/0816_GuptaPalanki/

Вы берете тест на это или что-то? Потому что это как минимум A + прямо здесь.

10
AnthonyJoeseph

Да. Утечки памяти все еще могут происходить, даже если у вас есть GC. Например, вы можете придерживаться таких ресурсов, как наборы результатов базы данных, которые вы должны закрыть вручную.

8
Markus Johnsson

Ответ звучит громко yes, но это, как правило, результат модель программирования, а не признак какого-либо дефекта в JVM. Это часто случается, когда у фреймворков жизненные циклы отличаются от жизненных циклов JVM. Вот некоторые примеры:

  1. Перезагрузка контекста
  2. Отсутствие разыменования наблюдателей (слушателей)
  3. Забыв очистить ресурсы после того, как вы их закончили

* - Миллиарды консалтинговых долларов были сделаны для разрешения последнего

5
jonathan.cone

Да, в том смысле, что ваше Java-приложение со временем может накапливать память, которую сборщик мусора не может освободить.

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

4
Tyler

да, если вы не отменяете ссылки на объекты, они никогда не будут собираться мусором и использование памяти увеличится. однако из-за того, как устроен Java, этого трудно достичь, в то время как в некоторых других языках это иногда трудно не достичь.

Правка: прочитать ссылку Амокране. хорошо.

3
pstanton

Книга Эффективная Java дает еще две причины "утечек памяти":

  • Как только вы поместите ссылку на объект в Cache и забудете, что она есть. Ссылка остается в кеше задолго до того, как становится неактуальной. Решение состоит в том, чтобы представить кэш в виде WeakHashMap
  • в API, где клиенты регистрируют обратные вызовы и не регистрируют их явно. Решение - хранить только слабые ссылки на них.
2
Trivikram

Краткий ответ:

У компетентной JVM нет памяти утечки, но можно использовать больше памяти чем необходимо, потому что не все неиспользованные объекты были собраны мусором, еще. Кроме того, сами приложения Java могут содержать ссылки на объекты, которые им больше не нужны, и это может привести к утечке памяти.

Еще более короткий ответ:

Ява является языком и не может иметь утечки памяти, только Java Virtual Машины могут.

2
Michael Goldshteyn

Да, это возможно.

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

2
dteoh

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

Примером этого было бы забыть закрыть открытый поток:

class MemoryLeak {

    private void startLeaking() throws IOException {
        StringBuilder input = new StringBuilder();
        URLConnection conn = new URL("www.example.com/file.txt").openConnection();

        BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream(), StandardCharsets.UTF_8));        

        while (br.readLine() != null) {
            input.append(br.readLine());
        }
    }

    public static void main(String[] args) throws IOException {
        MemoryLeak ml = new MemoryLeak();
        ml.startLeaking();
    }
}
1
Stas

Один простой ответ: JVM позаботится обо всей вашей инициализации POJO [простых старых объектов Java], если вы не работаете с JNI. С JNI, если вы сделали какое-то выделение памяти с помощью собственного кода, вы должны позаботиться об этой памяти самостоятельно.

0
Swaranga Sarma

Да. Утечка памяти - это неиспользуемая память, которая не передается диспетчеру памяти приложением.

Я много раз видел Java-код, который хранит элементы в структуре данных, но элементы никогда не удаляются оттуда, заполняя память до тех пор, пока не возникнет ошибка OutOfMemoryError:

void f() {
    List<Integer> w = new ArrayList<Integer>();
    while (true) {
         w.add(new Integer(42));
    }
}

Хотя этот пример слишком очевиден, ошибки памяти Java, как правило, более тонкие. Например, используя Dependency Injection для сохранения огромного объекта на компоненте с SESSION scope , не освобождая его, когда объект больше не используется.

На 64 битах VM это имеет тенденцию ухудшаться, поскольку пространство подкачки памяти начинает заполняться, пока система не сканирует слишком много операций IO.

0
vz0