Najprostszy sposób na spowodowanie wycieku pamięci w Javie? [duplikat]

to pytanie ma już odpowiedzi tutaj : Zamknięte 8 lat temu .

Możliwy duplikat:
Tworzenie wycieku pamięci za pomocą Javy

Jaki jest najprostszy sposób na spowodowanie wycieku pamięci java?

Author: Community, 2011-02-09

9 answers

Tak naprawdę nie można "wyciekać pamięci" w Javie, chyba że:

  • intern strings
  • generowanie klas
  • wyciek pamięci w kodzie natywnym wywołanym przez jni
  • zachowaj odniesienia do rzeczy, których nie chcesz w jakimś zapomnianym lub niejasnym miejscu.
Rozumiem, że interesuje Cię ostatnia sprawa. Typowe scenariusze to:
  • słuchaczy, zwłaszcza z klasami wewnętrznymi
  • caches.

Dobrym przykładem może być do:

    Tworzenie Swing gui, które uruchamia potencjalnie nieograniczoną liczbę okien modalnych;]}
  • niech okno modalne zrobi coś takiego podczas inicjalizacji: {[0]}

Zarejestrowana akcja nic nie robi, ale spowoduje, że okno modalne pozostanie w pamięci na zawsze, nawet po zamknięciu, powodując wyciek - ponieważ słuchacze nigdy nie są niezarejestrowani, a każdy anonimowy obiekt klasy wewnętrznej zawiera odniesienie (niewidoczne) do zewnętrznego obiektu. Co więcej-każdy obiekt odwołany z okien modalnych ma również szansę wycieku.

Dlatego biblioteki takie jak EventBus domyślnie używają słabych referencji.

Oprócz słuchaczy, innymi typowymi przykładami są pamięci podręczne, ale nie mogę wymyślić ładnego przykładu.

 34
Author: fdreger,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-02-09 20:20:58

"wyciek pamięci, w informatyce (lub w tym kontekście wyciek), występuje, gdy program komputerowy zużywa pamięć, ale nie jest w stanie zwolnić jej z powrotem do systemu operacyjnego."(Wikipedia)

Prosta odpowiedź brzmi: nie możesz. Java automatycznie zarządza pamięcią i zwalnia zasoby, które nie są ci potrzebne. Nie powstrzymasz tego. Zawsze będzie w stanie uwolnić zasoby. W programach z ręcznym zarządzaniem pamięcią jest inaczej. You cann get some memory w C używając malloc (). Aby uwolnić pamięć, potrzebny jest wskaźnik, który malloc zwrócił i wywołał na niej funkcję free (). Ale jeśli nie masz już wskaźnika (nadpisanego lub przekroczonego czasu życia), to niestety nie jesteś w stanie uwolnić tej pamięci, a tym samym masz wyciek pamięci.

Wszystkie pozostałe odpowiedzi do tej pory są w mojej definicji nie do końca wycieki pamięci. Wszyscy mają na celu zapełnienie pamięci bezsensownymi rzeczami naprawdę szybko. Ale w każdej chwili możesz nadal odwoływać się do utworzonych obiektów i tym samym uwolnienie pamięci -- > brak przecieku. odpowiedź acconrada jest dość bliska, ponieważ muszę przyznać, że jego rozwiązaniem jest po prostu "rozbicie" śmieciarza, zmuszając go do niekończącej się pętli).

Długa odpowiedź brzmi: można uzyskać wyciek pamięci, pisząc bibliotekę dla Javy za pomocą JNI, która może mieć ręczne zarządzanie pamięcią i tym samym mieć wycieki pamięci. Jeśli wywołasz tę bibliotekę, proces java spowoduje wyciek pamięci. Lub, można mieć błędy w JVM, tak, że JVM traci pamięć. Prawdopodobnie w JVM są błędy, mogą być nawet znane, ponieważ garbage collection nie jest aż tak trywialne, ale to i tak jest błąd. Z założenia nie jest to możliwe. Możesz poprosić o jakiś kod Javy, który jest wywołany przez taki błąd. Sorry nie znam żadnego I w następnej wersji Javy i tak może nie być już Bugiem.

 15
Author: yankee,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-02-09 18:12:23

Oto prosty przykład

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!");
        }
    }
}
 11
Author: acconrad,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-11-23 13:01:25
public static List<byte[]> list = new ArrayList<byte[]>();

A następnie dodaj (duże) tablice bez ich usuwania. W pewnym momencie zabraknie Ci pamięci bez podejrzeń. (Możesz to zrobić z dowolnymi obiektami, ale z dużymi, pełnymi tablicami możesz szybciej wyczerpać Pamięć)

W Javie, jeśli zdereferujesz obiekt (wypada poza zakres), jest on zbierany jako śmieci. Więc musisz trzymać odniesienie do niego, aby mieć problem z pamięcią.

 9
Author: Bozho,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-02-09 20:21:26
  1. tworzenie kolekcji obiektów w klasie scope
  2. okresowo dodawaj nowe obiekty do kolekcji
  3. nie opuszczaj odwołania do instancji klasy, która posiada zbiór

Ponieważ zawsze istnieje odniesienie do kolekcji I instancji obiektu, który jest właścicielem kolekcji, Garbage Collector nigdy nie wyczyści tej pamięci, powodując tym samym" wyciek " z czasem.

 3
Author: Paul Sasik,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-02-09 18:07:34

Z tego, co czytałem w najczęściej głosowanej odpowiedzi, prawdopodobnie prosisz o wyciek pamięci typu C. Cóż, ponieważ jest kolekcja garbagge, nie można przydzielić obiektu, stracić wszystkich jego odniesień i nadal zajmować pamięć - to byłby poważny błąd JVM.

Z drugiej strony, może zdarzyć się wyciek wątków-co, oczywiście, spowoduje ten stan, ponieważ będziesz miał jakiś wątek uruchomiony z jego odniesieniami do obiektów i możesz stracić odniesienie do wątku. Ty nadal można uzyskać odniesienie do wątku poprzez API - http://www.exampledepot.com/egs/java.lang/ListThreads.html

 3
Author: Ondra Žižka,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-02-09 18:08:13

Następująca niezwykle wymyślna klasa Box spowoduje wyciek pamięci, jeśli zostanie użyta. Obiekty, które są put do tej klasy są ostatecznie (po kolejnym wywołaniu put, aby być precyzyjnym... pod warunkiem, że ten sam obiekt nie zostanie ponownieput do niego.) niedostępne dla świata zewnętrznego. Nie mogą być zdelegalizowane przez tę klasę, ale ta klasa zapewnia, że nie mogą być zbierane. To prawdziwy przeciek. Wiem, że to jest naprawdę wymyślone, ale podobne przypadki można zrobić przez przypadek.

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();
    }
}
 1
Author: Thomas Eding,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-07-07 21:49:51

Spróbuj tej prostej klasy:

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
}
}
 0
Author: lukastymo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-02-09 18:08:55

Wydaje się, że większość odpowiedzi to nie wycieki pamięci w stylu C.

Pomyślałem, że dodam przykład klasy bibliotecznej z błędem, który da ci wyjątek out of memory. Ponownie, nie jest to prawdziwy wyciek pamięci, ale jest przykładem czegoś, czego nie można się spodziewać.

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

Oryginalny kod i opis błędu znajdziesz na

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

 0
Author: MrJacqes,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-02-09 22:56:31