Создание утечки памяти с Java - PullRequest
2986 голосов
/ 24 июня 2011

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

Каким будет пример?

Ответы [ 54 ]

6 голосов
/ 16 июля 2011

Одна из возможностей - создать оболочку для ArrayList, которая предоставляет только один метод: тот, который добавляет вещи в ArrayList.Сделайте ArrayList самим частным.Теперь создайте один из этих объектов-оболочек в глобальной области видимости (как статический объект в классе) и укажите для него ключевое слово final (например, public static final ArrayListWrapper wrapperClass = new ArrayListWrapper()).Так что теперь ссылка не может быть изменена.То есть wrapperClass = null не будет работать и не может использоваться для освобождения памяти.Но также нет способа сделать что-либо с wrapperClass, кроме добавления объектов к нему.Поэтому любые объекты, которые вы добавляете в wrapperClass, невозможно переработать.

6 голосов
/ 18 апреля 2017

Утечка памяти в java не является типичной утечкой памяти в C / C ++.

Чтобы понять, как работает JVM, прочитайте Общие сведения об управлении памятью .

В основномважная часть:

Модель Mark and Sweep

JVM JRockit использует модель сборки меток и очистки мусора для выполнения сборок мусора всей кучи.Сборка метки и очистки мусора состоит из двух фаз: фазы метки и фазы очистки.

На этапе метки все объекты, доступные из потоков Java, собственных дескрипторов и других корневых источников, помечаются какживы , а также объекты, которые достижимы от этих объектов и так далее. Этот процесс идентифицирует и помечает все объекты, которые все еще используются, а остальные могут считаться мусором.

Во время фазы развертки куча обходится, чтобы найти промежутки между живыми объектами.Эти пропуски записываются в свободном списке и становятся доступными для размещения новых объектов.

В JRockit JVM используются две улучшенные версии модели меток и разверток.Один в основном совпадает с меткой и разверткой, а другой - с параллельной меткой и разверткой.Вы также можете смешать две стратегии, например, в основном для одновременной метки и параллельной развертки.

Итак, чтобы создать утечку памяти в Java;самый простой способ сделать это - создать соединение с базой данных, выполнить некоторую работу и просто не Close() это;затем создайте новое соединение с базой данных, оставаясь в области видимости.Это не сложно сделать в цикле, например.Если у вас есть работник, который извлекает данные из очереди и передает их в базу данных, вы можете легко создать утечку памяти, забыв о Close() соединениях или открыв их, когда это не нужно, и т. Д.

В конце концов, вы 'Я буду использовать кучу, выделенную JVM, забыв Close() соединение.Это приведет к сбору мусора в JVM как сумасшедшему;в конечном итоге приводит к java.lang.OutOfMemoryError: Java heap space ошибкам.Следует отметить, что ошибка может не означать утечку памяти;это может означать, что у вас недостаточно памяти;базы данных, такие как Cassandra и ElasticSearch, например, могут выдавать эту ошибку, потому что у них недостаточно места в куче.

Стоит отметить, что это верно для всех языков GC.Ниже приведены некоторые примеры работы SRE:

  • Узел, использующий Redis в качестве очереди;Команда разработчиков создавала новые соединения каждые 12 часов и забыла закрыть старые.В конце концов узел был OOMd, потому что он занимал всю память.
  • Golang (я виновен в этом);парсинг больших файлов json с json.Unmarshal, а затем передача результатов по ссылке и их сохранение.В конечном итоге это привело к тому, что вся куча была поглощена случайными ссылками, которые я оставил открытыми для декодирования json.
5 голосов
/ 18 июня 2014

Метод String.substring в Java 1.6 создает утечку памяти.Это сообщение в блоге объясняет это.

http://javarevisited.blogspot.com/2011/10/how-substring-in-java-works.html

5 голосов
/ 01 июня 2012

В Java «утечка памяти» - это прежде всего просто то, что вы используете слишком много памяти, что отличается от того, что есть в C, где вы больше не используете память, но забыли вернуть (освободить) ее.Когда интервьюер спрашивает об утечках памяти Java, он спрашивает об использовании памяти JVM, которое, по-видимому, продолжает расти, и решает, что перезапуск JVM на регулярной основе является лучшим решением.(если интервьюер не крайне технически подкован)

Поэтому ответьте на этот вопрос так, как если бы они спросили, что заставляет использование памяти JVM расти со временем.Хорошие ответы будут хранить слишком много данных в HttpSessions с чрезмерно большим таймаутом или плохо реализованным кешем в памяти (Singleton), который никогда не сбрасывает старые записи.Другой потенциальный ответ - наличие большого количества JSP или динамически генерируемых классов.Классы загружаются в область памяти с именем PermGen, которая обычно невелика, и большинство JVM не осуществляют выгрузку классов.

5 голосов
/ 28 сентября 2012

Swing очень легко справляется с диалогами. Создайте JDialog, покажите его, пользователь закроет его, утечка! Вы должны позвонить dispose() или настроить setDefaultCloseOperation(DISPOSE_ON_CLOSE)

4 голосов
/ 09 июля 2013

Lapsed Listerners - хороший пример утечек памяти: объект добавлен в качестве слушателя.Все ссылки на объект обнуляются, когда объект больше не нужен.Однако, забыв удалить объект из списка прослушивателей, вы сохраните объект живым и даже отреагируете на события, что приведет к потере памяти и процессора.Смотри http://www.drdobbs.com/jvm/java-qa/184404011

4 голосов
/ 07 марта 2013

Если вы не используете компактный сборщик мусора, может произойти утечка памяти из-за фрагментации кучи.

4 голосов
/ 19 августа 2014

Неосторожное использование нестатического внутреннего класса внутри класса, который имеет свой жизненный цикл.

В Java нестатические внутренние и анонимные классы содержат неявную ссылку на свой внешний класс. Статические внутренние классы, с другой стороны, не .

Вот типичный пример утечки памяти в Android, который не очевиден:

public class SampleActivity extends Activity {

  private final Handler mLeakyHandler = new Handler() { //non-static inner class, holds the reference to the SampleActivity outter class
    @Override
    public void handleMessage(Message msg) {
      // ...
    }
  }

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    // Post a message and delay its execution for a long time.
    mLeakyHandler.postDelayed(new Runnable() {//here, the anonymous inner class holds the reference to the SampleActivity class too
      @Override
      public void run() {
     //.... 
      }
    }, SOME_TOME_TIME);

    // Go back to the previous Activity.
    finish();
  }}

Это предотвратит сбор мусора в контексте действия.

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

утечка памяти - это тип утечки ресурсов, который возникает, когда компьютерная программа неправильно управляет выделением памяти таким образом, что память, которая больше не нужна, не освобождается => определение вики

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

Первый пример должен быть пользовательским стеком без обнуления устаревших ссылок в эффективного элемента Java 6 .

КонечноЕсть еще много, сколько вы хотите, но если мы просто посмотрим на встроенные классы Java, это может быть что-то вроде

subList()

Давайте проверим супер глупый код, чтобы произвести утечку.

public class MemoryLeak {
    private static final int HUGE_SIZE = 10_000;

    public static void main(String... args) {
        letsLeakNow();
    }

    private static void letsLeakNow() {
        Map<Integer, Object> leakMap = new HashMap<>();
        for (int i = 0; i < HUGE_SIZE; ++i) {
            leakMap.put(i * 2, getListWithRandomNumber());
        }
    }



    private static List<Integer> getListWithRandomNumber() {
        List<Integer> originalHugeIntList = new ArrayList<>();
        for (int i = 0; i < HUGE_SIZE; ++i) {
            originalHugeIntList.add(new Random().nextInt());
        }
        return originalHugeIntList.subList(0, 1);
    }
}

На самом деле есть еще одна хитрость, которую мы можем вызвать утечку памяти, используя HashMap , воспользовавшись преимуществами его процесса поиска.На самом деле существует два типа:

  • hashCode() всегда одинаковы, но equals() различны;
  • используют random hashCode() и equals()всегда верно;

Почему?

hashCode() -> ведро => equals(), чтобы найти пару


Я собирался упомянуть сначала substring(), а затем subList(), но, похоже, эта проблема уже исправлена, поскольку ее источник представлен в JDK 8.

public String substring(int beginIndex, int endIndex) {
    if (beginIndex < 0) {
        throw new StringIndexOutOfBoundsException(beginIndex);
    }
    if (endIndex > value.length) {
        throw new StringIndexOutOfBoundsException(endIndex);
    }
    int subLen = endIndex - beginIndex;
    if (subLen < 0) {
        throw new StringIndexOutOfBoundsException(subLen);
    }
    return ((beginIndex == 0) && (endIndex == value.length)) ? this
            : new String(value, beginIndex, subLen);
}
0 голосов
/ 04 января 2013

Вот очень простая программа на Java, которой не хватит места

public class OutOfMemory {

    public static void main(String[] arg) {

        List<Long> mem = new LinkedList<Long>();
        while (true) {
            mem.add(new Long(Long.MAX_VALUE));
        }
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...