Kiedyś myślałem, że tak nie jest, ale wczoraj musiałem to zrobić. Jest to aplikacja korzystająca z Akka (implementacja systemu aktorów dla JVM) do przetwarzania zadań asynchronicznych. Jeden z aktorów wykonuje pewne manipulacje PDF, a ponieważ biblioteka jest błędna, umiera StackOverflowError
co jakiś czas.
Drugi aspekt polega na tym, że Akka jest skonfigurowane do zamykania całego systemu aktorów, jeśli zostanie wykryty błąd krytyczny JVM (np. StackOverflowError).
Trzecim aspektem jest to, że ten system aktorów jest osadzony w aplikacji internetowej (z powodu WTF, dziedzictwa, powodów), więc gdy system aktorów jest zamknięty, aplikacja internetowa nie. W efekcie StackOverflowError
nasza aplikacja do przetwarzania zadań staje się pustą aplikacją internetową.
Jako szybką poprawkę musiałem złapać StackOverflowError
rzucanego, aby pula wątków systemu aktorów nie została zerwana. Doprowadziło mnie to do wniosku, że może czasem dobrze jest wyłapać takie błędy, szczególnie w takich kontekstach? Kiedy pula wątków przetwarza dowolne zadania? W przeciwieństwie do OutOfMemoryError
nie mogę sobie wyobrazić, jak a StackOverflowError
może pozostawić aplikację w niespójnym stanie. Stos jest usuwany po takim błędzie, więc obliczenia mogą przebiegać normalnie. Ale może brakuje mi czegoś ważnego.
Pamiętajmy też, że przede wszystkim jestem za naprawieniem błędu (tak naprawdę kilka dni temu naprawiłem już SOE w tej samej aplikacji), ale tak naprawdę nie wiem, kiedy to może powstać taka sytuacja.
Dlaczego lepiej byłoby zrestartować proces JVM zamiast łapać StackOverflowError
, oznaczyć to zadanie jako nieudane i kontynuować moją działalność?
Czy jest jakiś ważny powód, aby nigdy nie łapać SOE? Z wyjątkiem „najlepszych praktyk”, które są niejasnym terminem, który nic mi nie mówi.
źródło
StackOverflowException
s są zwykle spowodowane nie kończącym się łańcuchem wywołań metod - zwiększenie przestrzeni stosu zwiększyłoby wówczas koszt pamięci nowego wątku bez żadnej korzyści.:-)
Odpowiedzi:
Zasadniczo, gdyby absolutnie nigdy, nigdy nie można było nic zrobić, i istniała zgoda co do tego, realizatorzy języków nie pozwoliliby na to. Prawie nie ma tak jednoznacznie jednoznacznych maksym. (Na szczęście, ponieważ to utrzymuje nas programiści ludzcy w pracy!)
Wygląda to tak, jakbyś znalazł sytuację, w której złapanie tego błędu jest najlepszą opcją: pozwala aplikacji działać, podczas gdy wszystkie inne alternatywy nie, i to się na końcu liczy. Wszystkie „najlepsze praktyki” to po prostu podsumowanie długich doświadczeń z wieloma przypadkami, które zwykle można zastosować zamiast szczegółowej analizy konkretnego przypadku, aby zaoszczędzić czas; w twoim przypadku wykonałeś już konkretną analizę i uzyskałeś inny wynik. Gratulacje, jesteś zdolny do samodzielnego myślenia!
(To powiedziawszy, z pewnością istnieją sytuacje, w których przepełnienie stosu może spowodować niespójność aplikacji, podobnie jak wyczerpanie pamięci. Wyobraź sobie, że jakiś obiekt jest konstruowany, a następnie inicjowany za pomocą zagnieżdżonych wewnętrznych wywołań metod - jeśli jedno z nich wyrzuci, obiekt może być w stanie, który nie powinien być możliwy, tak jak gdyby alokacja nie powiodła się. Ale to nie znaczy, że twoje rozwiązanie nie może być najlepsze.)
źródło
StackOverflowException
wyjątek, którego nie można złapać. Wiem, że to inna platforma, ale myślałem, że mogli mieć powód. Również twój punkt widzenia w odniesieniu do inicjalizacji obiektu jest natychmiastowy. To prowadzi mnie do myślenia, że powinienem złapać to SOE kilka warstw abstrakcji poniżej, aby nie złapać „złego” SOE.situations here
powinno byćsituations where
.Nie wiem, czy są tutaj jakieś ryzyka specyficzne dla JVM, ale ogólnie wydaje się to całkiem rozsądne.
Na przykład istnieją algorytmy rekurencyjne, takie jak naiwne szybkie sortowanie, które mają
log(n)
głębokość stosu w typowym przypadku, ale w najgorszym przypadku zmniejszają się do głębokości,n
która może wysadzić stos.Najgorszy przypadek jest rzadki i mało prawdopodobne jest, aby powtórzył się po ponownym uruchomieniu sortowania w częściowo posortowanym zestawie, więc sensowne jest wychwycenie wyjątku przepełnienia stosu i ponowne uruchomienie pracy zamiast zapobiegania wystąpieniu błędu lub zabiciu cała aplikacja.
źródło