Метод подстроки в классе String вызывает утечку памяти

Говорят, что метод substring в классе String вызывает утечку памяти. Это правда? Как? Что это за альтернатива?
В частности, поиск ответа,
Что это за другие вещи, которые могут вызвать утечку памяти в java? Это поможет мне позаботиться при кодировании.

Ответ 1

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

Этот метод теперь изменен, и эта "утечка" больше не существует.

Если вы хотите использовать старый JDK (который старше, чем OpenJDK 7, Update 6), и вы хотите иметь минимальные строки после substring, используйте конструктор, который принимает другую строку:

String s2 = new String(s1.substring(0,1));

Что касается вашего второго вопроса, касающегося "других вещей, которые могут вызвать утечку памяти в java", невозможно конструктивно ответить. В java standard libs не существует многих случаев, когда вы могли бы легко скрывать ссылки на объекты. В общем случае обратите внимание на все ссылки, которые вы создаете, наиболее часто возникающие проблемы, возникающие в неочищенных коллекциях или внешних ресурсах (файлы, транзакции базы данных, собственные виджеты и т.д.).

Ответ 2

Метод substring() не выделяет новый массив символов для String, а просто создает String с окном в существующий массив char. Это является следствием мухи и рассматривается как оптимизация.

Итак, если у меня есть огромный массив String (char), а затем создайте подстроку, даже если я мусор собираю исходную строку, исходный массив char останется (несмотря на то, что вы считаете, что у вас есть подстрока, скажем, 2 символа). Эта проблема часто встречается, когда (скажем) разбор огромного потока входных данных (возможно, файла XML) и извлечение небольшого количества текста через substring()

Использование, казалось бы, избыточного конструктора String(String str) (конструктор String с String!) разрешает это, поскольку он выделяет новый (потенциально меньший) массив char, позволяя оригиналу собирать мусор.

Обратите внимание, что это поведение изменилось с Java 7u6.

Ответ 3

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

Самое простое решение - использовать последнюю версию Java 7, которая этого не делает. Поскольку это единственная свободно поддерживаемая версия от Oracle, вы должны все равно сделать это.

Как таковой он был "исправлен" в обновлении Java 7 5. IMHO это не столько исправление, сколько упрощение реализации. Получение копии каждой подстроки требует гораздо больше работы и, скорее всего, потребляет больше памяти, но это означает, что есть еще одна проблема, о которой нужно беспокоиться.

Что это за другие вещи, которые могут вызвать утечку памяти в java?

Любой объект может быть очищен, поэтому невозможно создать утечку памяти в смысле C/С++. То, что вы можете сделать, это неправильно помещать объекты. Общим примером этого является забывание закрыть ресурсы, такие как ресурс JDBC. Это может привести к сохранению памяти так, как вы не ожидаете.

Ответ 4

В объекте String, когда вы вызываете substring, свойство value делится между двумя строками.

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