Ответ 1

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

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

Я полагаю, что вас интересует последний случай. Общие сценарии:

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

Хорошим примером может быть:

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

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

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

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

Ответ 2

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

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

Все остальные ответы до сих пор в моем определении не являются утечками памяти. Все они стремятся наполнить память бессмысленными вещами очень быстро. Но в любое время вы все равно можете разыменовать созданные вами объекты и освободить память → NO LEAK. Ответ acconrad довольно близок, хотя, как я должен признать, поскольку его решение эффективно просто "сбивает" сборщик мусора, заставляя его в бесконечном цикле).

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

Ответ 3

public static List<byte[]> list = new ArrayList<byte[]>();

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

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

Ответ 4

Здесь простой пример

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!");
        }
    }
}

Ответ 5

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

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

Ответ 6

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

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

Ответ 7

Добавить случайные целые числа в ArrayList в бесконечном цикле.

Ответ 8

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

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
}
}

Ответ 9

Кажется, что большинство ответов не являются утечками памяти стиля 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

Ответ 10

Следующий чрезвычайно надуманный класс Box будет утечка памяти при использовании. Объекты, которые 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();
    }
}