Сборка мусора – это процесс, посредством которого виртуальная машина Java определяет, какие объекты больше не используются в приложении, и продолжает удалять их из памяти, чтобы их можно было использовать для других целей. Исходя из этого, вы можете подумать, что утечки памяти в Java невозможны, но мы здесь.
Утечка памяти происходит, когда приложение больше не использует определенные объекты, но на них все еще ссылаются. Из-за этого они не могут быть удалены сборщиком мусора. С течением времени и продолжением работы приложения создается все больше и больше подобных объектов, пока доступная память не заполнится. Это может в конечном итоге привести к ошибке OutOfMemoryError, от которой невозможно оправиться.
Утечки памяти – одна из самых сложных проблем в приложениях Java. Их может быть легко не заметить и трудно обнаружить.
Как узнать, есть ли в вашем приложении утечка памяти
Если:
- Ваше приложение работает быстро, когда оно только начало работать, но со временем замедляется
- Ваше приложение хорошо справляется с небольшими наборами данных, но испытывает трудности с большими наборами данных
- Вы получаете ошибки Из кучи памяти
- В вашем приложении происходят случайные/странные сбои
…вероятно, где-то произошла утечка памяти.
Как я уже сказал, обнаружить утечки памяти может быть сложно, поэтому лучше их избегать. Я собираюсь рассказать вам о некоторых распространенных сценариях утечки памяти и рекомендуемых методах их предотвращения.
1. Интенсивное использование статических полей
Это классический сценарий утечки памяти, когда объекты Java создаются без освобождения. Статические ссылки сохраняются на протяжении всего жизненного цикла JVM, и поэтому объект не может быть удален из памяти.
Например:
public class StaticFieldMemoryLeak {
private static List integers = new ArrayList();
public void insertIntegers() {
for (int i = 0; i < 100000000; i++) {
integers.add(i);
}
}
public static void main(String[] args) {
StaticFieldMemoryLeak staticFieldMemoryLeak = new StaticFieldMemoryLeak();
staticFieldMemoryLeak.insertIntegers();
System.out.println("Done with inserting integers");
}
}
К тому времени, когда мы дойдем до строки, где мы пишем “Готово со вставкой целых чисел”, нам больше не понадобится наш список. Но поскольку список здесь является статическим полем, он никогда не будет собран сборщиком мусора, даже после выполнения каждой строки кода, в которой он используется.
Конечно, это небольшой пример с очень простой программой. Но представьте, что у вас есть большое приложение со сложными процессами, и в нем есть куча ненужных статических переменных. В этом случае вы будете использовать много ресурсов, которые можно было бы использовать для других целей, и у вас может закончиться память.
Теперь давайте рассмотрим тот же пример, но на этот раз мы объявим список как локальную переменную.
public class StaticFieldMemoryLeak {
public void insertIntegers() {
List integers = new ArrayList();
for (int i = 0; i < 100000000; i++) {
integers.add(i);
}
}
public static void main(String[] args) {
StaticFieldMemoryLeak staticFieldMemoryLeak = new StaticFieldMemoryLeak();
staticFieldMemoryLeak.insertIntegers();
System.out.println("Done with inserting integers");
}
}
В этом случае список будет использован, а затем должным образом удален, и сборщик мусора сможет восстановить память, которую он использовал. Поскольку это локальная переменная, когда мы достигаем точки кода, в которой переменная больше не используется, сборщик мусора определяет, что он может освободить память.
Как это предотвратить?
На этом этапе вы, вероятно, уже знаете: будьте внимательны к использованию статических переменных. Имейте в виду, что объявление объекта статическим означает, что его жизненный цикл привязан к жизненному циклу JVM.
2. Незакрытые ресурсы
Забывание закрыть поток или соединение – распространенная проблема, приводящая к утечкам памяти. Я бы сказал, что это тот, который я видел больше всего на практике.
Взгляните на этот пример:
public class UnclosedStream {
public void readFile() {
StringBuilder strBuilder = new StringBuilder();
URLConnection conn = new URL("http://testurl.com/large_file.txt").openConnection();
BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream(), StandardCharsets.UTF_8));
while (br.readLine() != null) {
strBuilder.append(br.readLine());
}
strBuilder = null;
}
public static void main(String[] args) {
UnclosedStream unclosedStream = new UnclosedStream();
unclosedStream.readFile();
System.out.println("Done with reading file");
}
}
По мере чтения файла использование памяти будет постепенно увеличиваться. Затем, поскольку BufferedReader никогда не закрывается, память не будет освобождена даже после того, как вы закончите чтение файла.
Это также может произойти с подключениями:
public class UnclosedConnection {
public void readFile() {
URL url = new URL("ftp://fakeaddr.net");
URLConnection urlConn = url.openConnection();
InputStream inputStream = urlConn.getInputStream();
}
public static void main(String[] args) {
UnclosedConnection unclosedConnection = new UnclosedConnection();
unclosedConnection.readFile();
System.out.println("Done with connecting");
}
}
Как вы можете видеть, соединение URL никогда не закрывается, поэтому оно остается открытым и содержит ресурсы памяти.
Как это предотвратить?
Просто, всегда помните, что либо:
- Закрывать потоки вручную
- Используйте try с ресурсами, представленными в Java 8:
try (BufferedReader br = new BufferedReader(
new InputStreamReader(conn.getInputStream(), StandardCharsets.UTF_8))) {
// whatever else you wanna do
} catch (IOException e) {
e.printStackTrace();
}
Это автоматически закроет BufferedReader в конце инструкции try.
3. Хэш-наборы и хэш-карты, сохраняющие ссылки на объекты живыми
Очень важной особенностью хэш-набора или хэш-карты является предотвращение дублирования элементов. Однако для того, чтобы это произошло, объекты, которые вы вставляете, должны иметь реализацию hashCode() и equals().
Если вы вставляете объекты без этих реализаций, становится невозможно определить, какие элементы дублируются. Это означает, что в конечном итоге вы можете добавить много ненужных объектов и увеличить вероятность утечки памяти.
Как это предотвратить?
Всегда добавляйте хэш-код() и реализацию equals() к своим объектам, если вы планируете поместить их в хэш-набор.
4. Вызов String.intern() для большой строки (до Java 8)
Метод String.intern() создает точную копию объекта String в памяти кучи и сохраняет ее в пуле строковых констант. Опять же, поскольку он хранится в памяти JVM, его нельзя собрать, и это может привести к тому, что сборщик мусора не сможет освободить достаточно памяти.
Если вам нужно хранить много больших строк в памяти JVM, подумайте об увеличении пространства PermGen.
В Java 8 пространство PermGen заменяется метапространством , что не приведет к ошибке OutOfMemory.
Как найти возможные утечки памяти в вашем приложении
Хорошо, допустим, вы имеете дело с приложением и подозреваете, что у вас утечка памяти. Как вы можете это выяснить?
1. Как вы можете это выяснить? Затмение
Как вы можете это выяснить? Eclipse Это относится к любому коду, совместимому с JDK 1.5+. Как вы можете это выяснить? Eclipse Это относится к любому коду, совместимому с JDK 1.5+. Eclipse предупредит вас о некоторых утечках памяти. Как вы можете это выяснить? Eclipse Это относится к любому коду, совместимому с JDK 1.5+. Eclipse предупредит вас о некоторых утечках памяти. Он выдаст предупреждение, если есть какой-либо объект, реализующий возможность закрытия, и ссылка будет уничтожена, но объект не закрыт.
Как вы можете это выяснить? Eclipse Это относится к любому коду, совместимому с JDK 1.5+. Eclipse предупредит вас о некоторых утечках памяти. Он выдаст предупреждение, если есть какой-либо объект, реализующий возможность закрытия, и ссылка будет уничтожена, но объект не закрыт. Чтобы включить это, перейдите в настройки Eclipse и установите следующее:
2. Как вы можете это выяснить? Eclipse Это относится к любому коду, совместимому с JDK 1.5+. Eclipse предупредит вас о некоторых утечках памяти. Он выдаст предупреждение, если есть какой-либо объект, реализующий возможность закрытия, и ссылка будет уничтожена, но объект не закрыт. Чтобы включить это, перейдите в настройки Eclipse и установите следующее: Подробная сборка мусора
Как вы можете это выяснить? Eclipse Это относится к любому коду, совместимому с JDK 1.5+. Eclipse предупредит вас о некоторых утечках памяти. Он выдаст предупреждение, если есть какой-либо объект, реализующий возможность закрытия, и ссылка будет уничтожена, но объект не закрыт. Чтобы включить это, перейдите в настройки Eclipse и установите следующее: Подробное описание Вы можете сделать это, включив параметр -verbose:gc в конфигурации JVM вашего приложения. возрастная коллекция Как вы можете это выяснить? Eclipse Это относится к любому коду, совместимому с JDK 1.5+. Eclipse предупредит вас о некоторых утечках памяти. Он выдаст предупреждение, если есть какой-либо объект, реализующий возможность закрытия, и ссылка будет уничтожена, но объект не закрыт. Чтобы включить это, перейдите в настройки Eclipse и установите следующее: Подробное описание Вы можете сделать это, включив параметр -verbose:gc JVЭТО позволит очень подробно отслеживать сборку мусора. M конфигурация вашего приложения. возрастная коллекция
3. Как вы можете это выяснить? Eclipse Это относится к любому коду, совместимому с JDK 1.5+. Eclipse предупредит вас о некоторых утечках памяти. Он выдаст предупреждение, если есть какой-либо объект, реализующий возможность закрытия, и ссылка будет уничтожена, но объект не закрыт. Чтобы включить это, перейдите в настройки Eclipse и установите следующее: Подробное описание Вы можете сделать это, включив параметр -verbose:gc в JVBenchmarking Это позволит очень подробно отслеживать сборку мусора. M конфигурация вашего приложения. возрастная коллекция
Как вы можете это выяснить? Eclipse Это относится к любому коду, совместимому с JDK 1.5+. Eclipse предупредит вас о некоторых утечках памяти. Он выдаст предупреждение, если есть какой-либо объект, реализующий возможность закрытия, и ссылка будет уничтожена, но объект не закрыт. Чтобы включить это, перейдите в настройки Eclipse и установите следующее: Подробное описание Вы можете сделать это, включив параметр -verbose:gc в JVBenchmarking, позволяющий измерять производительность разделов вашего кода. Сравнительный анализ Этого позволит очень подробно отслеживать сборку мусора. M конфигурация вашего приложения. возрастная коллекция Как вы можете это выяснить? Eclipse Это относится к любому коду, совместимому с JDK 1.5+. Eclipse предупредит вас о некоторых утечках памяти. Он выдаст предупреждение, если есть какой-либо объект, реализующий возможность закрытия, и ссылка будет уничтожена, но объект не закрыт. Чтобы включить это, перейдите в настройки Eclipse и установите следующее: Подробное описание Вы можете сделать это, включив параметр -verbose:gc в JVBenchmarking, позволяющий измерять производительность разделов вашего кода. Сравнительный анализ Этого позволит вам таким образом постоянно отслеживать его, чтобы выяснить, является ли какой-либо конкретный метод особенно медленным. y подробный отчет о сборе мусора. M конфигурация вашего приложения. возрастная коллекция Как вы можете это выяснить? Eclipse Это относится к любому коду, совместимому с JDK 1.5+. Eclipse предупредит вас о некоторых утечках памяти. Он выдаст предупреждение, если есть какой-либо объект, реализующий возможность закрытия, и ссылка будет уничтожена, но объект не закрыт. Чтобы включить это, перейдите в настройки Eclipse и установите следующее: Подробное описание Вы можете сделать это, включив параметр -verbose:gc в JVBenchmarking, позволяющий измерять производительность разделов вашего кода. Сравнительный анализ Это позволит вам постоянно отслеживать его, чтобы узнать, есть ли какие-либо особенности, если вы хотите узнать больше о сравнительном анализе в Java, перейдите по этой ссылке . метод ar особенно медленный. y подробный отчет о сборе мусора. M конфигурация вашего приложения. возрастная коллекция
4. Как вы можете это выяснить? Eclipse Это относится к любому коду, совместимому с JDK 1.5+. Eclipse предупредит вас о некоторых утечках памяти. Он выдаст предупреждение, если есть какой-либо объект, реализующий возможность закрытия, и ссылка будет уничтожена, но объект не закрыт. Чтобы включить это, перейдите в настройки Eclipse и установите следующее: Подробное описание Вы можете сделать это, включив параметр -verbose:gc в JVBenchmarking, позволяющий измерять производительность разделов вашего кода. Сравнительный анализ Это позволит вам постоянно отслеживать его, чтобы узнать, есть ли какие-либо особенности, если вы хотите узнать больше о сравнительном анализе в Java, || перейдите по этой ссылке || . метод ar особенно медленный. y подробный отчет о сборе мусора. M конфигурация вашего приложения. возрастная коллекция
Как вы можете это выяснить? Eclipse Это относится к любому коду, совместимому с JDK 1.5+. Eclipse предупредит вас о некоторых утечках памяти. Он выдаст предупреждение, если есть какой-либо объект, реализующий возможность закрытия, и ссылка будет уничтожена, но объект не закрыт. Чтобы включить это, перейдите в настройки Eclipse и установите следующее: Подробное описание Вы можете сделать это, включив параметр -verbose:gc в JVBenchmarking, позволяющий измерять производительность разделов вашего кода. Сравнительный анализ Этого позволит aver Таким образом, чтобы вы могли постоянно отслеживать его, чтобы выяснить, является ли какой-либо конкретный профилировщик Java инструментом, который отслеживает операции на уровне JVM, включая сборку мусора. Профилирование если вы хотите узнать больше о сравнительном анализе в Java, || перейдите по этой ссылке || . Метод ar особенно медленный. y подробный отчет о сборе мусора. M конфигурация вашего приложения. возрастная коллекция Как вы можете это выяснить? Eclipse Это относится к любому коду, совместимому с JDK 1.5+. Eclipse предупредит вас о некоторых утечках памяти. Он выдаст предупреждение, если есть какой-либо объект, реализующий возможность закрытия, и ссылка будет уничтожена, но объект не закрыт. Чтобы включить это, перейдите в настройки Eclipse и установите следующее: Подробное описание Вы можете сделать это, включив параметр -verbose:gc в JVBenchmarking, позволяющий измерять производительность разделов вашего кода. Сравнительный анализ Этого позволит aver Таким образом, чтобы вы могли постоянно отслеживать его, чтобы выяснить, является ли какой-либо конкретный профилировщик Java инструментом, который отслеживает операции на уровне JVM, включая сборку мусора. Профилирование, если вы хотите узнать больше, так как некоторые популярные из них – YourKit и VisualVM. что касается сравнительного анализа в Java, || перейдите по этой ссылке || . Метод ar особенно медленный. y подробный отчет о сборе мусора. M конфигурация вашего приложения. возрастная коллекция
5. Как вы можете это выяснить? Eclipse Это относится к любому коду, совместимому с JDK 1.5+. Eclipse предупредит вас о некоторых утечках памяти. Он выдаст предупреждение, если есть какой-либо объект, реализующий возможность закрытия, и ссылка будет уничтожена, но объект не закрыт. Чтобы включить это, перейдите в настройки Eclipse и установите следующее: Подробное описание Вы можете сделать это, включив параметр -verbose:gc в JVBenchmarking, позволяющий измерять производительность разделов вашего кода. Сравнительный анализ Этого позволит aver Таким образом, чтобы вы могли постоянно отслеживать его, чтобы выяснить, является ли какой-либо конкретный профилировщик Java инструментом, который отслеживает операции на уровне JVM, включая сборку мусора. Профилирование если вы хотите узнать больше о коде, просмотрите некоторые популярные из них – YourKit и VisualVM. что касается сравнительного анализа в Java, || перейдите по этой ссылке || . Метод ar особенно медленный. y подробный отчет о сборе мусора. M конфигурация вашего приложения. возрастная коллекция
Как вы можете это выяснить? Eclipse Это относится к любому коду, совместимому с JDK 1.5+. Eclipse предупредит вас о некоторых утечках памяти. Он выдаст предупреждение, если есть какой-либо объект, реализующий возможность закрытия, и ссылка будет уничтожена, но объект не закрыт. Чтобы включить это, перейдите в настройки Eclipse и установите следующее: Подробное описание Вы можете сделать это, включив параметр -verbose:gc в JVBenchmarking, позволяющий измерять производительность разделов вашего кода. Сравнительный анализ Этого позволит aver Таким образом, чтобы вы могли постоянно отслеживать его, чтобы выяснить, является ли какой-либо конкретный профилировщик Java инструментом, который отслеживает операции на уровне JVM, включая сборку мусора. Профилирование, если вы хотите узнать больше об этом, как правило, является хорошей практикой, но если вы пытаетесь найти утечки памяти, внимательно просмотрите код и попытайтесь привлечь другую пару глаз, чтобы также просмотреть его. Обзор кода Некоторые популярные из них – YourKit и VisualVM. что касается сравнительного анализа в Java, || перейдите по этой ссылке || . Метод ar особенно медленный. y подробный отчет о сборе мусора. M конфигурация вашего приложения. возрастная коллекция Как вы можете это выяснить? Eclipse Это относится к любому коду, совместимому с JDK 1.5+. Eclipse предупредит вас о некоторых утечках памяти. Он выдаст предупреждение, если есть какой-либо объект, реализующий возможность закрытия, и ссылка будет уничтожена, но объект не закрыт. Чтобы включить это, перейдите в настройки Eclipse и установите следующее: Подробное описание Вы можете сделать это, включив параметр -verbose:gc в JVBenchmarking, позволяющий измерять производительность разделов вашего кода. Сравнительный анализ Этого позволит aver Таким образом, чтобы вы могли постоянно отслеживать его, чтобы выяснить, является ли какой-либо конкретный профилировщик Java инструментом, который отслеживает операции на уровне JVM, включая сборку мусора. Профилирование если вы хотите узнать больше, вы можете заметить некоторые проблемы, о которых я здесь упоминал. Как правило, это хорошая практика, но если вы пытаетесь найти утечки памяти, внимательно изучите код и попытайтесь привлечь другую пару глаз, чтобы также просмотреть его. Обзор кода Некоторые популярные из них – YourKit и VisualVM. что касается сравнительного анализа в Java, || перейдите по этой ссылке || . Метод ar особенно медленный. y подробный отчет о сборе мусора. M конфигурация вашего приложения. возрастная коллекция
Как вы можете это выяснить? Eclipse Это относится к любому коду, совместимому с JDK 1.5+. Eclipse предупредит вас о некоторых утечках памяти. Он выдаст предупреждение, если есть какой-либо объект, реализующий возможность закрытия, и ссылка будет уничтожена, но объект не закрыт. Чтобы включить это, перейдите в настройки Eclipse и установите следующее: Подробное описание Вы можете сделать это, включив параметр -verbose:gc в JVBenchmarking, позволяющий измерять производительность разделов вашего кода. Сравнительный анализ Этого позволит aver Таким образом, чтобы вы могли постоянно отслеживать его, чтобы выяснить, является ли какой-либо конкретный профилировщик Java инструментом, который отслеживает операции на уровне JVM, включая сборку мусора. Профилирование если вы хотите узнать больше, я надеюсь, что это помогло вам узнать немного больше об утечках памяти и о том, как их избежать. Возможно, вы заметили некоторые из проблем, о которых я здесь упоминал. Как правило, это хорошая практика, но если вы пытаетесь найти утечки памяти, внимательно изучите код и попытайтесь привлечь другую пару глаз, чтобы также просмотреть его. Обзор кода Некоторые популярные из них – YourKit и VisualVM. что касается сравнительного анализа в Java, || перейдите по этой ссылке || . Метод ar особенно медленный. y подробный отчет о сборе мусора. M конфигурация вашего приложения. возрастная коллекция Как вы можете это выяснить? Eclipse Это относится к любому коду, совместимому с JDK 1.5+. Eclipse предупредит вас о некоторых утечках памяти. Он выдаст предупреждение, если есть какой-либо объект, реализующий возможность закрытия, и ссылка будет уничтожена, но объект не закрыт. Чтобы включить это, перейдите в настройки Eclipse и установите следующее: Подробное описание Вы можете сделать это, включив параметр -verbose:gc в JVBenchmarking, позволяющий измерять производительность разделов вашего кода. Сравнительный анализ Этого позволит aver Таким образом, чтобы вы могли постоянно отслеживать его, чтобы выяснить, является ли какой-либо конкретный профилировщик Java инструментом, который отслеживает операции на уровне JVM, включая сборку мусора. Профилирование если вы хотите узнать больше, если вы в настоящее время застряли, пытаясь найти один из них, удачи, дружище! Я надеюсь, что это помогло вам узнать немного больше об утечках памяти и о том, как их избежать. Возможно, вы заметили некоторые из проблем, о которых я здесь упоминал. Как правило, это хорошая практика, но если вы пытаетесь найти утечки памяти, внимательно изучите код и попытайтесь привлечь другую пару глаз, чтобы также просмотреть его. Обзор кода Некоторые популярные из них – YourKit и VisualVM. что касается сравнительного анализа в Java, || перейдите по этой ссылке || . Метод ar особенно медленный. y подробный отчет о сборе мусора. M конфигурация вашего приложения. возрастная коллекция
Оригинал: “https://dev.to/ca5th/memory-leaks-in-java-and-how-to-avoid-them-48h3”