Самый простой способ вызвать утечку памяти в Java?

Возможный дубликат:
Создание утечки памяти с Java

Какой самый простой способ вызвать утечку памяти Java?

9 ответов

Решение

Вы не можете "утечь память" в Java, если вы:

  • стажировка
  • генерировать классы
  • утечка памяти в нативном коде, названном jni
  • храните ссылки на вещи, которые вам не нужны, в каком-то забытом или непонятном месте.

Я так понимаю, что вы заинтересованы в последнем случае. Распространенные сценарии:

  • слушатели, особенно с внутренними классами
  • кэши.

Хорошим примером будет:

  • создать графический интерфейс Swing, который запускает потенциально неограниченное количество модальных окон;
  • сделать модальное окно сделать что-то вроде этого во время его инициализации:
    StaticGuiHelper.getMainApplicationFrame().getOneOfTheButtons().addActionListener(new ActionListener(){
      public void actionPerformed(ActionEvent e){
         // do nothing...
      }
    })
    

Зарегистрированное действие ничего не делает, но оно приведет к тому, что модальное окно останется в памяти навсегда, даже после закрытия, что приведет к утечке - поскольку слушатели никогда не регистрируются, и каждый анонимный объект внутреннего класса содержит ссылку (невидимую) на свой внешний объект., Более того, любой объект, на который ссылаются модальные окна, тоже имеет вероятность утечки.

Вот почему библиотеки, такие как EventBus, по умолчанию используют слабые ссылки.

Помимо слушателей, другими типичными примерами являются кеши, но я не могу придумать хороший пример.

"Утечка памяти в информатике (или утечка в этом контексте) происходит, когда компьютерная программа использует память, но не может вернуть ее обратно в операционную систему". (Википедия)

Простой ответ: вы не можете. Java выполняет автоматическое управление памятью и освобождает ресурсы, которые вам не нужны. Вы не можете остановить это. Он ВСЕГДА сможет освободить ресурсы. В программах с ручным управлением памятью это отличается. Вы не можете получить немного памяти в C, используя malloc(). Чтобы освободить память, вам нужен указатель, который возвратил malloc, и вызовите free() для него. Но если у вас больше нет указателя (перезаписано или превышено время жизни), то, к сожалению, вы не сможете освободить эту память и, следовательно, у вас будет утечка памяти.

Все остальные ответы, по моему мнению, на самом деле не утечки памяти. Все они стремятся заполнить память бессмысленными вещами очень быстро. Но в любой момент вы все равно можете разыменовать созданные вами объекты и, таким образом, освободить память -> НЕТ УТЕЧКИ. Ответ acconrad довольно близок, хотя, как я должен признать, его решение состоит в том, чтобы просто "сбить" сборщик мусора, запустив его в бесконечный цикл).

Длинный ответ: вы можете получить утечку памяти, написав библиотеку для Java с использованием JNI, которая может иметь ручное управление памятью и, таким образом, иметь утечки памяти. Если вы вызовете эту библиотеку, ваш процесс Java будет утечка памяти. Или вы можете иметь ошибки в JVM, так что JVM теряет память. Вероятно, есть ошибки в JVM, могут даже быть некоторые известные, так как сборка мусора не так уж тривиальна, но в то же время это все еще ошибка. По замыслу это невозможно. Вы можете попросить некоторый код Java, который вызван такой ошибкой. Извините, я не знаю ни одного, и в любом случае это может быть ошибкой в ​​следующей версии Java.

Вот простой пример

public class finalizer {
    @Override
        protected void finalize() throws Throwable {
        while (true) {
            Thread.yield();
        }
    }

    public static void main(String[] args) {
        while (true) {
            for (int i = 0; i < 100000; i++) {
                finalizer f = new finalizer();
            }

            System.out.println("" + Runtime.getRuntime().freeMemory() + " bytes free!");
        }
    }
}
public static List<byte[]> list = new ArrayList<byte[]>();

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

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

  1. Создать коллекцию объектов в области видимости класса
  2. Периодически добавлять новые объекты в коллекцию
  3. Не удаляйте ссылку на экземпляр класса, который содержит коллекцию

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

Из того, что я прочитал в ответе с наибольшим количеством голосов, вы, скорее всего, просите утечку памяти в стиле C. Что ж, поскольку существует коллекция garbagge, вы не можете выделить объект, потерять все его ссылки и получить его все еще занимающим память - это было бы серьезной ошибкой JVM.

С другой стороны, может случиться утечка потоков - что, конечно, вызовет это состояние, потому что у вас будет какой-то поток, работающий с его ссылками на объекты, и вы можете потерять ссылку на поток. Вы все еще можете получить ссылку на Thread через API - http://www.exampledepot.com/egs/java.lang/ListThreads.html

Следующее чрезвычайно надуманное Box класс будет пропускать память, если используется. Объекты, которые put в этот класс в конце концов (после очередного звонка put чтобы быть точным... при условии, что тот же объект не повторноput в это.) недоступный для внешнего мира. Они не могут быть разыменованы через этот класс, но этот класс гарантирует, что они не могут быть собраны. Это НАСТОЯЩАЯ утечка. Я знаю, что это действительно надумано, но подобные случаи можно сделать случайно.

import java.util.ArrayList;
import java.util.Collection;
import java.util.Stack;

public class Box <E> {
    private final Collection<Box<?>> createdBoxes = new ArrayList<Box<?>>();
    private final Stack<E> stack = new Stack<E>();

    public Box () {
        createdBoxes.add(this);
    }

    public void put (E e) {
        stack.push(e);
    }

    public E get () {
        if (stack.isEmpty()) {
            return null;
        }
        return stack.peek();
    }
}

Попробуйте этот простой класс:

public class Memory {
private Map<String, List<Object>> dontGarbageMe = new HashMap<String, List<Object>>();

public Memory() {
    dontGarbageMe.put("map", new ArrayList<Object>());
}

public void useMemInMB(long size) {
    System.out.println("Before=" + getFreeMemInMB() + " MB");

    long before = getFreeMemInMB();
    while ((before  - getFreeMemInMB()) < size) { 
        dontGarbageMe.get("map").add("aaaaaaaaaaaaaaaaaaaaaa");
    }

    dontGarbageMe.put("map", null);

    System.out.println("After=" + getFreeMemInMB() + " MB");
}

private long getFreeMemInMB() {
    return Runtime.getRuntime().freeMemory() / (1024 * 1024);
}

public static void main(String[] args) {
    Memory m = new Memory();
    m.useMemInMB(15);  // put here apropriate huge value
}
}

Похоже, что большинство ответов не утечки памяти в стиле C.

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

public class Scratch {
    public static void main(String[] args) throws Exception {
        long lastOut = System.currentTimeMillis();
        File file = new File("deleteme.txt");

        ObjectOutputStream out;
        try {
            out = new ObjectOutputStream(
                    new FileOutputStream("deleteme.txt"));

            while (true) {
                out.writeUnshared(new LittleObject());
                if ((System.currentTimeMillis() - lastOut) > 2000) {
                    lastOut = System.currentTimeMillis();
                    System.out.println("Size " + file.length());
                    // out.reset();
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

class LittleObject implements Serializable {
    int x = 0;
}

Вы найдете оригинальный код и описание ошибки на

http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4363937

Другие вопросы по тегам