Tworzenie wycieku pamięci za pomocą Javy

Właśnie miałem wywiad i poproszono mnie o stworzenie wycieku pamięci za pomocą Javy. Nie trzeba dodawać, że czułem się całkiem głupi, nie mając pojęcia, jak zacząć je tworzyć.

Jaki byłby przykład?

Author: Mat Banik, 2011-06-24

30 answers

Oto dobry sposób na stworzenie prawdziwego wycieku pamięci (obiektów niedostępnych przez uruchomienie kodu, ale nadal przechowywanych w pamięci) w czystej Javie:

  1. aplikacja tworzy długotrwały wątek (lub użyj puli wątków, aby przeciekać jeszcze szybciej).
  2. wątek ładuje klasę za pomocą (opcjonalnie niestandardowego) Classloadera.
  3. klasa przydziela dużą część pamięci (np. new byte[1000000]), przechowuje silne odniesienie do niej w statycznym polu, a następnie przechowuje odniesienie do siebie w ThreadLocal. Przydzielanie dodatkowej pamięci jest opcjonalne( przeciekanie instancji klasy wystarczy), ale spowoduje to, że wyciek będzie działał znacznie szybciej.
  4. wątek czyści wszystkie odniesienia do klasy niestandardowej lub Classloadera, z którego został załadowany.
  5. Powtórz.

Działa to, ponieważ ThreadLocal zachowuje odniesienie do obiektu, które zachowuje odniesienie do swojej klasy, która z kolei zachowuje odniesienie do swojego Classloadera. ClassLoader z kolei zachowuje odniesienie do wszystkich klas, które posiada załadowany.

(było gorzej w wielu implementacjach JVM, szczególnie przed Javą 7, ponieważ klasy i Classloadery były przydzielane bezpośrednio do permgen i nigdy nie były GC ' D w ogóle. Jednak niezależnie od tego, jak JVM radzi sobie z rozładowywaniem klas, ThreadLocal nadal uniemożliwi odzyskanie obiektu klasy.)

Odmianą tego wzorca jest to, że kontenery aplikacji (takie jak Tomcat) mogą wyciekać pamięć jak sito, jeśli często zmieniasz aplikacje, które używają ThreadLocals w jakikolwiek sposób. (Ponieważ kontener aplikacji używa wątków zgodnie z opisem, a przy każdym ponownym uruchomieniu aplikacji używany jest nowy ClassLoader.)

Update: ponieważ wiele osób wciąż o to prosi, oto przykładowy kod, który pokazuje to zachowanie w działaniu.

 1994
Author: Daniel Pryden,
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
2017-09-06 02:56:18

Pole statyczne przechowujące odniesienie do obiektu [ostateczne pole esp]

class MemorableClass {
    static final ArrayList list = new ArrayList(100);
}

Calling String.intern() na długim sznurku

String str=readString(); // read lengthy string any source db,textbox/jsp etc..
// This will place the string in memory pool from which you can't remove
str.intern();

(Unclosed) otwarte strumienie (plik, sieć itp... )

try {
    BufferedReader br = new BufferedReader(new FileReader(inputFile));
    ...
    ...
} catch (Exception e) {
    e.printStacktrace();
}

Połączenia nierozłączone

try {
    Connection conn = ConnectionFactory.getConnection();
    ...
    ...
} catch (Exception e) {
    e.printStacktrace();
}

Obszary, które nie są dostępne z modułu garbage collector JVM , takie jak pamięć przydzielana za pomocą metod natywnych

W aplikacjach webowych niektóre obiekty są przechowywane w zakresie aplikacji aż do aplikacja jest wyraźnie zatrzymana lub usunięta.

getServletContext().setAttribute("SOME_MAP", map);

W przeciwieństwie do JVM, w JDK IBM nie można używać opcji JVM, które są niepoprawne lub nieodpowiednie, np. opcjanoclassgc, która zapobiega zbieraniu nieużywanych klas

Zobacz ustawienia IBM jdk .

 1087
Author: Prashant Bhate,
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
2018-01-30 23:32:27

Prostą rzeczą jest użycie HashSet z niepoprawnym (lub nieistniejącym) hashCode() lub equals(), a następnie dodawanie "duplikatów". Zamiast ignorować duplikaty tak, jak powinno, zestaw będzie tylko rosnąć i nie będzie można ich usunąć.

Jeśli chcesz, aby te złe klucze / elementy wisiały wokół ciebie, możesz użyć statycznego pola, takiego jak

class BadKey {
   // no hashCode or equals();
   public final String key;
   public BadKey(String key) { this.key = key; }
}

Map map = System.getProperties();
map.put(new BadKey("key"), "value"); // Memory leak even if your threads die.
 405
Author: Peter Lawrey,
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-06-24 21:50:56

Poniżej znajduje się nieoczywisty przypadek, w którym Java przecieka, oprócz standardowego przypadku zapomnianych słuchaczy, statycznych odniesień, fałszywych/modyfikowanych kluczy w hashmapach lub po prostu wątków, które utkwiły bez żadnej szansy na zakończenie cyklu życia.

  • File.deleteOnExit() - zawsze wycieka łańcuch, jeśli łańcuch jest podłańcuchem, wyciek jest jeszcze gorszy (znak [] jest również wyciekany) - w Javie 7 substring również kopiuje char[], więc później nie stosuje się ; @ Daniel, no needs na głosy.

Skoncentruję się na wątkach, aby pokazać niebezpieczeństwo niezarządzanych wątków głównie, Nie chcę nawet dotykać swinga.

  • Runtime.addShutdownHook i nie usuwać... a potem nawet z removeShutdownHook z powodu błędu w klasie ThreadGroup w odniesieniu do niezarejestrowanych wątków może nie zostać zebrany, skutecznie wyciek ThreadGroup. JGroup ma przeciek w Gossprouter.

  • Tworzenie, ale nie Uruchamianie, a Thread przechodzi do tej samej kategorii co powyżej.

  • Tworzenie wątku dziedziczy ContextClassLoader i AccessControlContext, plus ThreadGroup i dowolne InheritedThreadLocal, wszystkie te odwołania są potencjalnymi wyciekami, wraz z całymi klasami załadowanymi przez classloader i wszystkimi statycznymi odniesieniami oraz ja-ja. Efekt jest szczególnie widoczny w całym frameworku J.U. c. Executor, który posiada super prosty interfejs ThreadFactory, jednak większość programistów nie ma pojęcia o czyhającym niebezpieczeństwie. Również wiele bibliotek uruchamia wątki na żądanie (zbyt wiele branży biblioteki popularne).

  • ThreadLocal caches; są one złe w wielu przypadkach. Jestem pewien, że każdy widział sporo prostych pamięci podręcznych opartych na ThreadLocal, dobrze zła wiadomość: jeśli wątek będzie działał więcej niż oczekiwano życia classloader context, jest to czysty miły mały wyciek. Nie używaj pamięci podręcznych ThreadLocal, chyba że jest to naprawdę potrzebne.

  • Wywołanie ThreadGroup.destroy(), gdy grupa wątków sama nie ma wątków, ale nadal utrzymuje grupy wątków potomnych. Zły wyciek, który zapobiegnie ThreadGroup to remove from its parent, but all the children become un-enumerateable.

  • Użycie WeakHashMap i wartość (in) bezpośrednio odwołuje się do klucza. Ciężko go znaleźć bez wysypiska śmieci. Dotyczy to wszystkich rozszerzonych Weak/SoftReference, które mogą zachować twarde odniesienie do strzeżonego obiektu.

  • Używanie {[12] } z protokołem HTTP(S) i ładowanie zasobu z(!). Ten jest wyjątkowy, KeepAliveCache tworzy nowy wątek w systemie ThreadGroup który wycieka z bieżącego wątku ' s context classloader. Wątek jest tworzony na pierwsze żądanie, gdy nie istnieje żaden żywy wątek, więc albo możesz mieć szczęście, albo po prostu przeciekać. wyciek jest już naprawiony w Javie 7, a kod tworzący wątek prawidłowo usuwa classloader kontekstowy. jest jeszcze kilka przypadków (Jak ImageFetcher, poprawiono również ) tworzenie podobnych wątków.

  • Użycie InflaterInputStream przekazywanie new java.util.zip.Inflater() w konstruktorze (PNGImageDecoder na przykład) i nie wywołanie end() nadmuchiwacza. Jeśli zdasz konstruktora tylko new, nie ma szans... I tak, wywołanie close() na strumieniu nie zamyka inflatera, jeśli jest ręcznie przekazywane jako parametr konstruktora. To nie jest prawdziwy przeciek, ponieważ zostanie wydany przez finalizer... kiedy uzna to za konieczne. Do tej pory zżera on natywną pamięć tak bardzo, że może spowodować, że Linux oom_killer zabije proces bezkarnie. Głównym problemem jest to, że finalizacja w Javie jest bardzo zawodna i G1 pogorszyło do 7.0.2. Morał z tej historii: uwolnij natywne zasoby tak szybko, jak to możliwe; finalizator jest po prostu zbyt biedny.

  • Ten sam przypadek z java.util.zip.Deflater. Ten jest o wiele gorszy, ponieważ Deflater jest głodny pamięci w Javie, tzn. zawsze używa 15 bitów (max) i 8 poziomów pamięci (9 to max) przydzielających kilkaset KB pamięci natywnej. Na szczęście Deflater nie jest szeroko stosowany i według mojej wiedzy JDK nie zawiera żadnych nadużyć. Zawsze wywołaj end(), jeśli ręcznie tworzysz Deflater lub Inflater. Najlepsza część ostatnich dwóch: nie można ich znaleźć za pomocą zwykłych narzędzi do profilowania.

(na życzenie mogę dodać jeszcze kilka marnotrawstw Czasu, które napotkałem.)

[[25]} powodzenia i bądź bezpieczny; przecieki są złe!
 237
Author: bestsss,
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
2016-02-16 15:52:26

Większość przykładów tutaj jest "zbyt złożona". Są to skrajne przypadki. Z tymi przykładami programista popełnił błąd (np. nie redefiniuj equals / hashcode) lub został ugryziony przez narożną literę JVM/JAVA (load of class with static...). Myślę, że to nie jest typ przykład ankieter chce lub nawet najczęstszym przypadku.

Ale są naprawdę prostsze przypadki wycieków pamięci. Garbage collector uwalnia tylko to, czego już nie ma. My jako programiści Javy nie dbamy o pamięć. Przydzielamy go w razie potrzeby i pozwalamy na jego automatyczne uwolnienie. Dobrze.

Ale każda długotrwała aplikacja zwykle ma wspólny stan. To może być wszystko, statyka, singletony... Często nietrywialne aplikacje mają tendencję do tworzenia złożonych wykresów obiektów. Wystarczy zapomnieć o ustawieniu odniesienia do null lub częściej zapomnieć o usunięciu jednego obiektu z kolekcji, aby spowodować wyciek pamięci.

Oczywiście wszelkiego rodzaju słuchacze( jak UI listeners), pamięci podręczne lub jakiekolwiek długo żyjące Stany wspólne mają tendencję do wycieku pamięci, jeśli nie są prawidłowo obsługiwane. Należy rozumieć, że nie jest to przypadek Java corner, ani problem z garbage collector. Jest to problem projektowy. Projektujemy, że dodajemy słuchacza do długotrwałego obiektu, ale nie usuwamy słuchacza, gdy nie jest już potrzebny. Buforujemy obiekty, ale nie mamy strategii usuwania ich z pamięci podręcznej.

Być może mamy złożony wykres, który przechowuje poprzedni stan, który jest potrzebny do obliczeń. Ale poprzedni stan jest sama powiązana z Państwem wcześniej i tak dalej.

Jakbyśmy musieli zamknąć połączenia SQL lub pliki. Musimy ustawić odpowiednie odwołania do null i usunąć elementy z kolekcji. Będziemy mieli odpowiednie strategie buforowania (maksymalny rozmiar pamięci, ilość elementów lub timerów). Wszystkie obiekty, które pozwalają na powiadomienie słuchacza, muszą zawierać zarówno metodę addListener, jak i removeListener. A gdy osoby zgłaszające nie są już używane, muszą wyczyścić swoją listę słuchaczy.

Wyciek pamięci jest rzeczywiście naprawdę możliwe i jest całkowicie przewidywalne. Nie ma potrzeby stosowania specjalnych funkcji językowych ani narożników. Wycieki pamięci są albo wskaźnikiem, że może czegoś brakuje lub nawet problemów projektowych.

 165
Author: Nicolas Bousquet,
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
2018-02-13 07:27:47

Odpowiedź zależy całkowicie od tego, co rozmówca myślał, że pyta.

Czy w praktyce możliwe jest spowodowanie wycieku Javy? Oczywiście, że tak, i jest wiele przykładów w innych odpowiedziach.

Ale jest wiele meta-pytań, które mogły być zadawane?

  • czy teoretycznie "doskonała" implementacja Javy jest podatna na przecieki?
  • Czy kandydat rozumie różnicę między teorią a rzeczywistością? Czy kandydat rozumiesz, jak działa wywóz śmieci?
  • Albo jak ma działać śmieciarka w idealnym przypadku?
  • czy wiedzą, że mogą wywoływać inne języki przez natywne interfejsy?
  • czy wiedzą, aby wyciekać pamięć w tych innych językach?
  • czy kandydat w ogóle wie, czym jest zarządzanie pamięcią i co dzieje się za sceną w Javie?

Czytam Twoje meta-pytanie jako "Jaka jest odpowiedź, której mógłbym użyć w tej sytuacji wywiadu". Oraz dlatego zamierzam skupić się na umiejętności rozmowy kwalifikacyjnej zamiast Javy. Uważam, że bardziej prawdopodobne jest powtórzenie sytuacji, gdy nie znasz odpowiedzi na pytanie w wywiadzie, niż to, że jesteś w miejscu, w którym musisz wiedzieć, jak zrobić wyciek Javy. Mam nadzieję, że to pomoże.

Jedną z najważniejszych umiejętności, które możesz rozwinąć podczas rozmowy kwalifikacyjnej, jest nauka aktywnego słuchania pytań i praca z ankieterem w celu wyodrębnienia ich intencji. Nie tylko pozwala to odpowiedzieć na ich pytanie, jak chcą, ale również pokazuje, że masz kilka istotnych umiejętności komunikacyjnych. A jeśli chodzi o wybór pomiędzy wieloma równie utalentowanymi programistami, zatrudnię osobę, która słucha, myśli i rozumie, zanim za każdym razem odpowie.

 138
Author: PlayTank,
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
2015-01-27 12:52:33

Poniższy przykład jest dość bezsensowny, jeśli nie rozumiesz JDBC . A przynajmniej jak JDBC oczekuje od dewelopera zamknięcia Connection, Statement i ResultSet instancji przed ich odrzuceniem lub utratą odniesień do nich, zamiast polegać na implementacji finalize.

void doWork()
{
   try
   {
       Connection conn = ConnectionFactory.getConnection();
       PreparedStatement stmt = conn.preparedStatement("some query"); // executes a valid query
       ResultSet rs = stmt.executeQuery();
       while(rs.hasNext())
       {
          ... process the result set
       }
   }
   catch(SQLException sqlEx)
   {
       log(sqlEx);
   }
}

Problem z powyższym polega na tym, że obiekt Connection nie jest zamknięty, a zatem fizyczne połączenie pozostanie otwarte, dopóki nie pojawi się garbage collector i nie zobaczy, że jest nieosiągalny. GC wywoła metodę finalize, ale istnieją sterowniki JDBC, które nie implementują finalize, przynajmniej nie w taki sam sposób, jak zaimplementowano Connection.close. Wynikiem tego zachowania jest to, że podczas gdy pamięć zostanie odzyskana z powodu nieosiągalnych obiektów, zasoby (w tym pamięć) związane z obiektem Connection mogą po prostu nie zostać odzyskane.

W takim przypadku, gdy metoda Connection s finalize nie oczyszcza wszystkiego, można rzeczywiście stwierdzić, że fizyczne połączenie z serwer bazodanowy będzie trwał kilka cykli zbierania śmieci, dopóki serwer bazodanowy ostatecznie nie zorientuje się, że połączenie nie jest żywe (jeśli tak się stanie) i powinno zostać zamknięte.

Nawet jeśli sterownik JDBC miałby zaimplementować finalize, możliwe jest wyrzucenie WYJĄTKÓW podczas finalizacji. Wynikiem tego zachowania jest to, że pamięć powiązana z obecnie "uśpionym" obiektem nie zostanie odzyskana, ponieważ finalize jest gwarantowana, że zostanie wywołana tylko raz.

Powyższy scenariusz napotkanie WYJĄTKÓW podczas finalizacji obiektów jest związane z innym innym scenariuszem, który może prowadzić do wycieku pamięci - obiekt resurrection. Zmartwychwstanie obiektu jest często wykonywane celowo, tworząc silne odniesienie do obiektu z finalizowanego, z innego obiektu. Gdy obiekt resurrection zostanie niewłaściwie użyty, doprowadzi to do wycieku pamięci w połączeniu z innymi źródłami wycieków pamięci.

Jest jeszcze wiele przykładów, które można wyczarować - jak

  • Zarządzanie instancją List, w której dodajesz tylko do listy, a nie usuwasz z niej (chociaż powinieneś pozbyć się elementów, których już nie potrzebujesz), lub
  • otwieranie Sockets lub File s, ale nie zamykanie ich, gdy nie są już potrzebne (podobnie jak w powyższym przykładzie dotyczącym klasy Connection).
  • Nie rozładowuję singletonów podczas ściągania aplikacji Java EE. Najwyraźniej Classloader, który załadował klasę singleton, zachowa odniesienie do klasy, a zatem instancja Singletona nigdy nie zostanie zebrana. Gdy nowa instancja aplikacji jest wdrażana, zwykle tworzony jest nowy class loader, a poprzedni class loader będzie nadal istnieć ze względu na singleton.
 117
Author: Vineet Reynolds,
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
2016-02-16 15:38:36

Prawdopodobnie jednym z najprostszych przykładów potencjalnego wycieku pamięci i jak go uniknąć, jest implementacja ArrayList.remove (int):

public E remove(int index) {
    RangeCheck(index);

    modCount++;
    E oldValue = (E) elementData[index];

    int numMoved = size - index - 1;
    if (numMoved > 0)
        System.arraycopy(elementData, index + 1, elementData, index,
                numMoved);
    elementData[--size] = null; // (!) Let gc do its work

    return oldValue;
}

Gdybyś sam ją implementował, pomyślałbyś o wyczyszczeniu elementu tablicy, który nie jest już używany (elementData[--size] = null)? To odniesienie może utrzymać ogromny obiekt przy życiu ...

 106
Author: meriton,
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
2015-09-01 04:50:05

Za każdym razem, gdy przechowujesz odniesienia do obiektów, których już nie potrzebujesz, masz wyciek pamięci. Zobacz Handling memory leaks in Java programs aby dowiedzieć się, jak wycieki pamięci przejawiają się w Javie i co można z tym zrobić.

 64
Author: Bill the Lizard,
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-06-24 16:18:07

Jesteś w stanie zrobić wyciek pamięci z sun.misc.Klasa niebezpieczna . W rzeczywistości ta klasa usług jest używana w różnych standardowych klasach (na przykład w java.NIO klasy). nie możesz utworzyć instancji tej klasy bezpośrednio , ale możesz użyć do tego reflection .

Kod nie kompiluje się w Eclipse IDE-kompiluje go za pomocą polecenia javac (podczas kompilacji otrzymasz ostrzeżenia)

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import sun.misc.Unsafe;


public class TestUnsafe {

    public static void main(String[] args) throws Exception{
        Class unsafeClass = Class.forName("sun.misc.Unsafe");
        Field f = unsafeClass.getDeclaredField("theUnsafe");
        f.setAccessible(true);
        Unsafe unsafe = (Unsafe) f.get(null);
        System.out.print("4..3..2..1...");
        try
        {
            for(;;)
                unsafe.allocateMemory(1024*1024);
        } catch(Error e) {
            System.out.println("Boom :)");
            e.printStackTrace();
        }
    }

}
 46
Author: stemm,
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
2016-01-05 08:37:35

Mogę skopiować odpowiedź stąd: najprostszy sposób na spowodowanie wycieku pamięci w Javie?

"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. Nie możesz uzyskać trochę pamięci 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. Wszystkie mają na celu wypełnienie pamięci z bezsensownymi rzeczami naprawdę szybko. Ale w każdej chwili możesz jeszcze wyzerować obiekty, które utworzyłeś i tym samym uwolnić pamięć -- > NO LEAK. [[9]}odpowiedź acconrada jest dość bliska, jak muszę przyznać, ponieważ 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łanie tej biblioteki spowoduje wyciek pamięci w procesie Javy. Możesz też mieć błędy w JVM, dzięki czemu 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.

 40
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
2017-05-23 11:47:29

Oto prosty/złowrogi przez http://wiki.eclipse.org/Performance_Bloopers#String.substring.28.29 .

public class StringLeaker
{
    private final String muchSmallerString;

    public StringLeaker()
    {
        // Imagine the whole Declaration of Independence here
        String veryLongString = "We hold these truths to be self-evident...";

        // The substring here maintains a reference to the internal char[]
        // representation of the original string.
        this.muchSmallerString = veryLongString.substring(0, 1);
    }
}

Ponieważ podłańcuch odnosi się do wewnętrznej reprezentacji oryginalnego, znacznie dłuższego łańcucha, oryginał pozostaje w pamięci. Tak więc, tak długo, jak masz StringLeaker w grze, masz cały oryginalny ciąg w pamięci, zbyt, nawet jeśli możesz myśleć, że jesteś po prostu trzymając się jednego znaku łańcucha.

Sposób na uniknięcie przechowywania niechcianych odniesienie do oryginalnego ciągu znaków to zrobić coś takiego:

...
this.muchSmallerString = new String(veryLongString.substring(0, 1));
...

Dla dodanego zła, możesz również .intern() substring:

...
this.muchSmallerString = veryLongString.substring(0, 1).intern();
...

Spowoduje to zachowanie zarówno oryginalnego długiego ciągu, jak i pochodnego podłańcucha w pamięci nawet po odrzuceniu instancji StringLeaker.

 33
Author: Jon Chambers,
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-21 19:00:35

Częstym przykładem tego w kodzie GUI jest tworzenie widżetu / komponentu i dodawanie słuchacza do jakiegoś obiektu o zasięgu statycznym/aplikacji, a następnie nie usuwanie słuchacza po zniszczeniu widżetu. Nie tylko dostajesz wyciek pamięci, ale także hit wydajności, gdy cokolwiek słuchasz zdarzeń pożarów, wszyscy twoi starzy słuchacze są również nazywane.

 33
Author: pauli,
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
2016-02-16 15:40:24

Weź dowolną aplikację webową działającą w dowolnym kontenerze serwletów (Tomcat, Jetty, Glassfish, cokolwiek...). Przesuń aplikację 10 lub 20 razy z rzędu (może wystarczyć dotknięcie wojny w katalogu autodeploy serwera.

Chyba, że ktoś faktycznie przetestował to, są duże szanse, że dostaniesz OutOfMemoryError po kilku przesunięciach, ponieważ aplikacja nie zadbała o to, aby posprzątać po sobie. Możesz nawet znaleźć błąd na serwerze z tym test.

Problem polega na tym, że żywotność kontenera jest dłuższa niż żywotność aplikacji. Musisz upewnić się, że wszystkie odniesienia kontenera do obiektów lub klas aplikacji mogą być zbierane jako śmieci.

Jeśli istnieje tylko jedno odniesienie, które przetrwało nieudostępnienie Twojej aplikacji internetowej, odpowiedni classloader, a w konsekwencji wszystkie klasy Twojej aplikacji internetowej, nie mogą być zbierane.

Wątki rozpoczęte przez Twoją aplikację, ThreadLocal zmienne, appendery logowania są jednymi z typowych podejrzanych o powodowanie wycieków classloader.

 32
Author: Harald Wellmann,
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-03 22:41:17

Może używając zewnętrznego kodu natywnego poprzez JNI?

Z czystą Javą jest to prawie niemożliwe.

Ale chodzi o "standardowy" typ wycieku pamięci, gdy nie można uzyskać dostępu do pamięci, ale nadal jest ona własnością aplikacji. Zamiast tego można zachować odniesienia do nieużywanych obiektów lub otwartych strumieni bez ich zamykania.

 29
Author: Rogach,
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-06-24 21:48:48

Miałem ładny "wyciek pamięci" w odniesieniu do PermGen i XML parsingu raz. Parser XML, którego użyliśmy (nie pamiętam, który to był) zrobił Łańcuch znaków.intern() na nazwach znaczników, aby dokonać porównania szybciej. Jeden z naszych klientów wpadł na świetny pomysł, aby przechowywać wartości danych nie w atrybutach XML lub tekście, ale jako nazwy, więc mieliśmy dokument w stylu:

<data>
   <1>bla</1>
   <2>foo</>
   ...
</data>

W rzeczywistości nie używali liczb, ale dłuższych identyfikatorów tekstowych (około 20 znaków), które były unikalne i pojawiły się w tempie 10-15 milionów dzień. To sprawia, że 200 MB śmieci dziennie, co nigdy nie jest potrzebne ponownie ,i nigdy GCed (ponieważ jest w PermGen). Mieliśmy permgen ustawiony na 512 MB, więc zajęło około dwóch dni, zanim pojawił się wyjątek out-of-memory (OOME)...

 28
Author: Ron,
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
2016-02-16 15:44:24

Ostatnio spotkałem się z problemem wycieku pamięci spowodowanym w jakiś sposób przez log4j.

Log4j posiada mechanizm o nazwie Nested Diagnostic Context (NDC) , który jest instrumentem do rozróżniania przekładanych danych wyjściowych z różnych źródeł. Ziarnistość, przy której pracuje NDC, to wątki, więc odróżnia wyjścia dziennika od różnych wątków oddzielnie.

W celu przechowywania znaczników specyficznych dla wątku, Klasa log4j NDC używa Hashtable, która jest kluczowana przez sam obiekt wątku (jako w przeciwieństwie do ID wątku), a więc dopóki znacznik NDC nie pozostanie w pamięci, wszystkie obiekty, które zwisają z obiektu wątku, również pozostają w pamięci. W naszej aplikacji internetowej używamy NDC do oznaczania logoutputs za pomocą identyfikatora żądania, aby odróżnić logi od pojedynczego żądania osobno. Kontener, który kojarzy znacznik NDC z wątkiem, usuwa go również podczas zwracania odpowiedzi z żądania. Problem wystąpił, gdy w trakcie przetwarzania żądania powstał wątek potomny, coś w rodzaju następujący kod:

pubclic class RequestProcessor {
    private static final Logger logger = Logger.getLogger(RequestProcessor.class);
    public void doSomething()  {
        ....
        final List<String> hugeList = new ArrayList<String>(10000);
        new Thread() {
           public void run() {
               logger.info("Child thread spawned")
               for(String s:hugeList) {
                   ....
               }
           }
        }.start();
    }
}    

Więc kontekst NDC był związany z wątkiem inline, który został wywołany. Obiekt thread, który był kluczem dla tego kontekstu NDC, jest wątkiem inline, który ma obiekt hugeList zwisający z niego. Stąd nawet po tym, jak wątek skończył robić to, co robił, odniesienie do hugeList było utrzymywane przy życiu przez kontekst NDC, powodując w ten sposób wyciek pamięci.

 22
Author: Puneet,
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
2014-03-07 21:29:39

Myślałem, że to ciekawe, że nikt nie używał wewnętrznych przykładów klasy. Jeśli masz klasę wewnętrzną; z natury utrzymuje odniesienie do klasy zawierającej. Oczywiście nie jest to technicznie wyciek pamięci, ponieważ Java w końcu go wyczyści; ale może to spowodować, że klasy będą się kręcić dłużej niż przewidywano.

public class Example1 {
  public Example2 getNewExample2() {
    return this.new Example2();
  }
  public class Example2 {
    public Example2() {}
  }
}

Teraz, jeśli wywołasz Przykład1 i otrzymasz przykład2 odrzucający Przykład1, z natury będziesz miał link do obiektu Przykład1.

public class Referencer {
  public static Example2 GetAnExample2() {
    Example1 ex = new Example1();
    return ex.getNewExample2();
  }

  public static void main(String[] args) {
    Example2 ex = Referencer.GetAnExample2();
    // As long as ex is reachable; Example1 will always remain in memory.
  }
}

I ' ve słyszałem również plotkę, że jeśli masz zmienną, która istnieje dłużej niż określony czas; Java zakłada, że zawsze będzie istnieć i w rzeczywistości nigdy nie będzie próbował go wyczyścić, jeśli nie można już osiągnąć w kodzie. Ale to jest zupełnie nieweryfikowalne.

 21
Author: Suroot,
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-09 01:23:55

Co to jest wyciek pamięci:

    Jest to spowodowane przez błąd lub zły projekt. To strata pamięci.
  • z czasem się pogarsza.
  • Śmieciarz nie może go wyczyścić.

typowy przykład:

Pamięć podręczna obiektów jest dobrym punktem wyjścia do bałagan rzeczy.

private static final Map<String, Info> myCache = new HashMap<>();

public void getInfo(String key)
{
    // uses cache
    Info info = myCache.get(key);
    if (info != null) return info;

    // if it's not in cache, then fetch it from the database
    info = Database.fetch(key);
    if (info == null) return null;

    // and store it in the cache
    myCache.put(key, info);
    return info;
}

Twoja pamięć podręczna rośnie i rośnie. I wkrótce cała baza danych zostaje zasysana do pamięci. Lepszy projekt wykorzystuje LRUMap (Przechowuje tylko ostatnio używane obiekty w pamięci podręcznej).

Jasne, można zrobić rzeczy o wiele bardziej skomplikowane:

  • za pomocą konstrukcji ThreadLocal .
  • Dodawanie kolejnych złożonych drzew referencyjnych.
  • lub wycieków spowodowanych przezbiblioteki stron trzecich .

co często się dzieje:

Jeśli ten obiekt Info ma odniesienia do innych obiektów, które ponownie mają odniesienia do innych obiektów. W pewien sposób można również uznać, że jest to jakiś wycieku pamięci (spowodowanego złym projektem).

 20
Author: bvdb,
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
2014-10-28 13:18:50

Utwórz statyczną mapę i dodawaj do niej twarde odniesienia. To nigdy nie będzie GC ' D.

public class Leaker {
    private static final Map<String, Object> CACHE = new HashMap<String, Object>();

    // Keep adding until failure.
    public static void addToCache(String key, Object value) { Leaker.CACHE.put(key, value); }
}
 17
Author: duffymo,
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-21 17:32:58

Możesz utworzyć ruchomy wyciek pamięci, tworząc nową instancję klasy w metodzie finalize tej klasy. Punkty bonusowe, jeśli finalizator utworzy wiele instancji. Oto prosty program, który przecieka całą stertę w czasie od kilku sekund do kilku minut w zależności od rozmiaru sterty: {]}

class Leakee {
    public void check() {
        if (depth > 2) {
            Leaker.done();
        }
    }
    private int depth;
    public Leakee(int d) {
        depth = d;
    }
    protected void finalize() {
        new Leakee(depth + 1).check();
        new Leakee(depth + 1).check();
    }
}

public class Leaker {
    private static boolean makeMore = true;
    public static void done() {
        makeMore = false;
    }
    public static void main(String[] args) throws InterruptedException {
        // make a bunch of them until the garbage collector gets active
        while (makeMore) {
            new Leakee(0).check();
        }
        // sit back and watch the finalizers chew through memory
        while (true) {
            Thread.sleep(1000);
            System.out.println("memory=" +
                    Runtime.getRuntime().freeMemory() + " / " +
                    Runtime.getRuntime().totalMemory());
        }
    }
}
 16
Author: sethobrien,
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-22 08:05:07

Ankieter prawdopodobnie szukał okrągłego odniesienia, takiego jak poniższy kod (który nawiasem mówiąc, tylko przecieka pamięć w bardzo starych JVMs, które używały zliczania referencji, co już nie ma miejsca). Ale to dość niejasne pytanie, więc jest to doskonała okazja, aby pokazać swoje zrozumienie zarządzania pamięcią JVM.

class A {
    B bRef;
}

class B {
    A aRef;
}

public class Main {
    public static void main(String args[]) {
        A myA = new A();
        B myB = new B();
        myA.bRef = myB;
        myB.aRef = myA;
        myA=null;
        myB=null;
        /* at this point, there is no access to the myA and myB objects, */
        /* even though both objects still have active references. */
    } /* main */
}

Wtedy możesz wyjaśnić, że z liczeniem referencji powyższy kod wycieka pamięć. Ale większość nowoczesnych JVM nie używa już zliczania referencji, większość użyj sweep garbage collector, który w rzeczywistości zbierze tę pamięć.

Następnie możesz wyjaśnić tworzenie obiektu, który ma podstawowy natywny zasób, jak poniżej:

public class Main {
    public static void main(String args[]) {
        Socket s = new Socket(InetAddress.getByName("google.com"),80);
        s=null;
        /* at this point, because you didn't close the socket properly, */
        /* you have a leak of a native descriptor, which uses memory. */
    }
}

Więc możesz wyjaśnić, że jest to technicznie wyciek pamięci, ale tak naprawdę wyciek jest spowodowany natywnym kodem w JVM przydzielającym podstawowe zasoby natywne, które nie zostały uwolnione przez Twój kod Java.

Na koniec dnia, z nowoczesnym JVM, trzeba napisać jakiś kod Java, który przydziela natywny zasoby poza normalnym zakresem świadomości JVM.

 16
Author: deltamind106,
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
2017-10-13 19:09:24

Wszyscy zawsze zapominają o natywnym kodzie. Oto prosty wzór na wyciek:

  1. Declare native method.
  2. w natywnej metodzie wywołaj malloc. Nie dzwoń free.
  3. Wywołanie natywnej metody.

Pamiętaj, alokacje pamięci w kodzie natywnym pochodzą ze sterty JVM.

 15
Author: Paul Morie,
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-21 20:52:40

Ostatnio natknąłem się na bardziej subtelny rodzaj wycieku zasobów. Otwieramy zasoby poprzez getResourceAsStream klasy loader i zdarzyło się, że obsługa strumienia wejściowego nie została zamknięta.

Uhm, można powiedzieć, co za idiota.

Cóż, co sprawia, że jest to interesujące, to: w ten sposób możesz wyciekać pamięć sterty procesu, a nie z sterty JVM.

Wszystko czego potrzebujesz to plik jar z plikiem wewnątrz którego będzie się odwoływać z kodu Javy. Im większy plik jar, im szybciej zostanie przydzielona pamięć.

Możesz łatwo utworzyć taki jar za pomocą następującej klasy:

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

public class BigJarCreator {
    public static void main(String[] args) throws IOException {
        ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(new File("big.jar")));
        zos.putNextEntry(new ZipEntry("resource.txt"));
        zos.write("not too much in here".getBytes());
        zos.closeEntry();
        zos.putNextEntry(new ZipEntry("largeFile.out"));
        for (int i=0 ; i<10000000 ; i++) {
            zos.write((int) (Math.round(Math.random()*100)+20));
        }
        zos.closeEntry();
        zos.close();
    }
}

Wystarczy wkleić do pliku o nazwie BigJarCreator.java, skompilować i uruchomić z linii poleceń:

javac BigJarCreator.java
java -cp . BigJarCreator

Et voilà: znajdziesz archiwum Jar w bieżącym katalogu roboczym z dwoma plikami w środku.

Stwórzmy drugą klasę:

public class MemLeak {
    public static void main(String[] args) throws InterruptedException {
        int ITERATIONS=100000;
        for (int i=0 ; i<ITERATIONS ; i++) {
            MemLeak.class.getClassLoader().getResourceAsStream("resource.txt");
        }
        System.out.println("finished creation of streams, now waiting to be killed");

        Thread.sleep(Long.MAX_VALUE);
    }

}

Ta klasa w zasadzie nic nie robi, ale tworzy nieuregulowane obiekty InputStream. Te obiekty będą zbierane śmieci natychmiast, a tym samym nie przyczyniają się do wielkości stosu. Ważne jest, aby nasz przykład załadował istniejący zasób z pliku jar, a rozmiar ma tutaj znaczenie!

Jeśli masz wątpliwości, spróbuj skompilować i uruchomić klasę powyżej, ale upewnij się, że wybrałeś przyzwoity rozmiar sterty (2 MB):

javac MemLeak.java
java -Xmx2m -classpath .:big.jar MemLeak

Nie napotkasz tutaj błędu OOM, ponieważ żadne referencje nie są przechowywane, aplikacja będzie działać bez względu na to, jak duże wybrałeś iteracje w powyższym przykładzie. Zużycie pamięci Twojego process (widoczny w top (RES/RSS) lub process explorer) rośnie, chyba że aplikacja dostanie się do polecenia wait. W konfiguracji powyżej przeznaczy około 150 MB pamięci.

Jeśli chcesz, aby aplikacja była bezpieczna, Zamknij strumień wejściowy bezpośrednio tam, gdzie jest utworzona:

MemLeak.class.getClassLoader().getResourceAsStream("resource.txt").close();

I twój proces nie przekroczy 35 MB, niezależnie od liczby iteracji.

Dość proste i zaskakujące.
 15
Author: Jay,
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
2012-09-12 20:07:37

Myślę, że nikt jeszcze tego nie powiedział: możesz wskrzesić obiekt, nadpisując metodę finalize() tak, że finalize() przechowuje gdzieś odniesienie do tego obiektu. Garbage collector zostanie wywołany tylko raz na obiekcie, więc po tym obiekt nigdy nie zostanie zniszczony.

 14
Author: Ben,
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-03 17:36:58

Jak wiele osób zasugerowało, wycieki zasobów są dość łatwe do spowodowania - jak przykłady JDBC. Rzeczywiste wycieki pamięci są nieco trudniejsze - zwłaszcza jeśli nie polegasz na uszkodzonych bitach JVM, aby zrobić to za Ciebie...

Idee tworzenia obiektów, które mają bardzo duże rozmiary, a następnie nie mają do nich dostępu, również nie są prawdziwymi wyciekami pamięci. Jeśli nic nie ma do niego dostępu to będzie to śmieci zbierane, a jeśli coś ma do niego dostęp to nie jest przeciek...

Jednym ze sposobów, któryużył do pracy - i nie wiem, czy nadal działa - jest posiadanie trzy-głębokiego okrągłego łańcucha. Podobnie jak w obiekcie A ma odniesienie do obiektu B, obiekt B ma odniesienie do obiektu C, A obiekt C ma odniesienie do obiektu A. Gc był na tyle sprytny, że wiedział, że dwa głębokie łańcuchy-jak w B-mogą być bezpiecznie zebrane, jeśli A i B nie są dostępne przez cokolwiek innego, ale nie radzi sobie z łańcuchem trójdrożnym...

 14
Author: Graham,
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-21 17:55:51

Jest wiele różnych sytuacji, w których pamięć wycieka. Taką, którą napotkałem, która eksponuje mapę, która nie powinna być eksponowana i używana w innym miejscu.

public class ServiceFactory {

private Map<String, Service> services;

private static ServiceFactory singleton;

private ServiceFactory() {
    services = new HashMap<String, Service>();
}

public static synchronized ServiceFactory getDefault() {

    if (singleton == null) {
        singleton = new ServiceFactory();
    }
    return singleton;
}

public void addService(String name, Service serv) {
    services.put(name, serv);
}

public void removeService(String name) {
    services.remove(name);
}

public Service getService(String name, Service serv) {
    return services.get(name);
}

// the problematic api, which expose the map.
//and user can do quite a lot of thing from this api.
//for example, create service reference and forget to dispose or set it null
//in all this is a dangerous api, and should not expose 
public Map<String, Service> getAllServices() {
    return services;
}

}

// resource class is a heavy class
class Service {

}
 11
Author: Ben Xu,
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-10 07:46:03

Wątki nie są zbierane, dopóki się nie zakończą. Służą one jako korzenie zbierania śmieci. Są jednym z niewielu obiektów, których nie można odzyskać po prostu zapominając o nich lub usuwając odniesienia do nich.

Rozważ: podstawowym wzorcem zakończenia wątku roboczego jest ustawienie zmiennej warunkowej widzianej przez wątek. Wątek może okresowo sprawdzać zmienną i używać jej jako sygnału do zakończenia. Jeżeli zmienna nie jest zadeklarowana volatile, to zmiana na zmienna może nie być widziana przez wątek, więc nie będzie wiedział, aby zakończyć. Albo wyobraź sobie, że niektóre wątki chcą zaktualizować obiekt współdzielony, ale blokują się podczas próby zablokowania go.

Jeśli masz tylko kilka wątków, te błędy będą prawdopodobnie oczywiste, ponieważ twój program przestanie działać poprawnie. Jeśli masz pulę wątków, która tworzy więcej wątków w razie potrzeby, wtedy przestarzałe/zablokowane wątki mogą nie zostać zauważone i będą gromadzić się w nieskończoność, powodując wyciek pamięci. Wątki są prawdopodobnie wykorzysta inne dane w Twojej aplikacji, dzięki czemu zapobiegnie zbieraniu wszystkiego, do czego bezpośrednio się odwołują.

Jako przykład zabawki:

static void leakMe(final Object object) {
    new Thread() {
        public void run() {
            Object o = object;
            for (;;) {
                try {
                    sleep(Long.MAX_VALUE);
                } catch (InterruptedException e) {}
            }
        }
    }.start();
}

Wywołaj System.gc() ile chcesz, ale obiekt przekazany do leakMe nigdy nie umrze.

(*edited*)

 11
Author: Boann,
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
2017-05-23 12:02:58

Myślę, że dobrym przykładem może być użycie zmiennych ThreadLocal w środowisku, w którym wątki są łączone.

Na przykład, używając zmiennych ThreadLocal w Serwletach do komunikacji z innymi komponentami sieci web, mając wątki tworzone przez kontener i utrzymując te bezczynne w Puli. Zmienne ThreadLocal, jeśli nie zostaną prawidłowo wyczyszczone, będą tam żyć, dopóki ten sam komponent web nie nadpisze ich wartości.

Oczywiście po zidentyfikowaniu problem można łatwo rozwiązać.

 9
Author: mschonaker,
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-03 06:49:51

Ankieter mógł szukać okrągłego rozwiązania odniesienia:

    public static void main(String[] args) {
        while (true) {
            Element first = new Element();
            first.next = new Element();
            first.next.next = first;
        }
    }

Jest to klasyczny problem z liczeniem referencji śmieciarki. Następnie uprzejmie wyjaśnisz, że JVMs używa znacznie bardziej wyrafinowanego algorytmu, który nie ma tego ograniczenia.

- Wes Tarle

 9
Author: Wesley Tarle,
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-04 15:06:58