Zrobmy maly challenge: jaki znacie najlatwiejsze albo najciekawszy/najfajniejszy sposob na zrobienie w Javie memory leaka?
Update: zalozmy ze jesli autor odpowiedzi nie zaznaczy inaczej przyjmujemy za punt wyjsciowy Jave 8 z domyslnym GC.
Zrobmy maly challenge: jaki znacie najlatwiejsze albo najciekawszy/najfajniejszy sposob na zrobienie w Javie memory leaka?
Update: zalozmy ze jesli autor odpowiedzi nie zaznaczy inaczej przyjmujemy za punt wyjsciowy Jave 8 z domyslnym GC.
Najpopularniejszy:
Nie uzycie try-with-resources
Najłatwiejszy:
Dodawanie do hash struktur obiektu ktory nie ma hashCode/equals
Najbardziej paskudny: (bo te wyzej to nawet jetbrains wychwyci, chociaż z niewiadomych mi przyczyn ludzie notorycznie nie patrza na jego hinty)
Dać osobie nie znającej C++ zrobić bindingi do JNI do native C++. (memory leak praktycznie gwarantowany)
void leakMemory() throws NoSuchFieldException, IllegalAccessException {
Field f = Unsafe.class.getDeclaredField("theUnsafe");
f.setAccessible(true);
((Unsafe) f.get(null)).allocateMemory(99999);
}
Co wygrałem? :-)
Robisz sobie jakis sprytny cache na mapie i nigdy nic z niego nie usuwasz...
Chyba że mówimy o takich "celowych" z użyciem unsafe czy odwołań do natywnego kodu.
tworzenie:
Executors.newFixedThreadPool (lub inej puli)
np podczas wywołań metod.
Pule wątków (oraz i wątki) cały czas sobie istnieją.
Żeby było śmieszniej można pododawać ThreadLocal i nie wiadomo co gdzie jest.
Pule nie są zwalniane i jak dobrze pamiętam są to root obieky dla GC stąd nie są automatycznie odśmiecane nawet jak się im przypisze nulla.
public class PoolLeak {
private static ThreadLocal<int[]> val = new ThreadLocal<>();
private static void doSomething() {
ExecutorService execs = Executors.newFixedThreadPool(100);
for(int i = 0; i < 100; i++) {
execs.execute(() -> {
val.set(new int[ 1000]);
});
}
execs = null;
}
public static void main(String[] args) throws Exception {
for(int i = 0; i < 10000000; i++) {
doSomething();
}
}
}
Exception in thread "RMI TCP Connection(idle)" java.lang.OutOfMemoryError: Java heap space
at java.lang.Class.getDeclaredMethods0(Native Method)
interface Interfejs {
int metoda();
}
class BardzoCiężkaKlasa {
private final int[] tablica = new int[BARDZO_DUŻO];
Interfejs nibyNiewinnaMetoda() {
return new Interfejs { // klasa anonimowa ma niejawny wskaźnik do otaczającej klasy, tutaj powodujący tylko i wyłącznie wyciek
int metoda() {
return 5;
}
}
}
}
class InnaKlasa {
private final Interfejs instancja = new BardzoCiężkaKlasa().nibyNiewinnaMetoda(); // tutaj jest wyciek klasy BardzoCiężkaKlasa, która jest tutaj niepotrzebna
}
Najprościej i najpewniej to nowy wątek z while(true) w środku i ciężkim polem.