2015-03-18 26 views
8

Kontekst:Co zrobić, aby Perl nie zużywał ton pamięci po wyłączeniu widełek dużego procesu nadrzędnego?

Mam multi-rozwidlone Perl (5,16) Proces, który działa na Linux. Widget nadrzędny ładuje bardzo dużą ilość kodu Perla (przez use/require) i przydziela wiele struktur danych (kilka GB). Następnie tworzy wiele rozwidleń dla dzieci, z których wszystkie działają równolegle. Odbywa się to w celu zmniejszenia śladu pamięciowego procesu podczas jego działania, ponieważ funkcja kopiowania przy zapisie z dnia fork() oznacza, że ​​dzieci mogą korzystać z danych, które posiada rodzic, bez utrzymywania własnego dużego obrazu pamięci.

Problem:

Wszystko to działa dobrze, dopóki próbuję zamknąć grupę procesów. Kiedy przerywam rodzic (sygnał propaguje się do wszystkich dzieci), pamięć serwera uruchamiającego kod natychmiast się zapełnia, zaczyna się zamieniać, a inne procesy na serwerze mielą się do zatrzymania. Gdy widelec do kopiowania na piśmie zostanie zamknięty, Perl wydaje się próbować ponownie przydzielić całą pamięć zarezerwowaną w systemie nadrzędnym, aby można go było zgłosić pod kątem free lub coś podobnego.

Pytanie:

Jak mogę zapobiec uwędzić na zamknięciu dzieje? Czy jest jakiś sposób, by powiedzieć dziecinnym widelcom, że próbują tylko przechodzić i odzyskiwać pamięć, którą przydzielono te widełki?

+1

Czy rodzic powinien najpierw złapać sygnał i wyłączyć dzieci? – Schwern

Odpowiedz

10

Przydział stron pamięci wynika z deallokacji zmiennych przy wyjściu. Jest to konieczne do wywołania destruktorów.

Wywołanie POSIX::_exit() spowoduje natychmiastowe wyjście, pomijanie przypisań między zmiennymi, ale także pomijanie wywołań destruktorów.

2

Przyjąłem odpowiedź @ ikegami, ponieważ bezpośrednio odpowiada na pytanie.

Zamieszczam to, ponieważ moje "rozwiązanie" (naprawdę sposób na zoptymalizowanie części problemu) może być przydatne dla innych.

Ewentualne poprawki w moim przypadku był to zmiana paradygmatu: zdałem sobie sprawę, że problemem nie było to, że każdyproces Perl zasysa dużo pamięci na widelec wyłączeniu, ale miałem tylu Perl przetwarza ssania do pamięci przy wyłączaniu w tym samym czasie.

Kiedy mój proces macierzysty otrzymał instrukcję "shutdown", natychmiast wysłał komunikat "shutdown" do wszystkich swoich dzieci, a oni wszyscy skończyli to, co robili i zamknęli mniej więcej w tym samym czasie. W dowolnym miejscu od dziesiątek do setek procesów potomnych zamykanych w tym samym czasie, narzut pamięci był zbyt duży.

Rozwiązano problem polegający na zamknięciu procesu dwufazowego: najpierw proces nadrzędny wysłał wiadomość "stop what you doing" do wszystkich swoich dzieci, aby logika biznesowa przestała działać w przewidywalnym czasie. Wysłał tę wiadomość do wszystkich dzieci naraz/w bardzo szybkiej pętli. Następnie zamknęło one dzieci po jednym na raz. Wystąpiło przerwanie dla każdego dziecka, o nazwie waitpid, dopóki nie skończyło się, a następnie przejdzie do następnego.

W ten sposób, w najgorszym przypadku zamknięcie wywołane ślad pamięć (p reprezentujących wstępnie widelca zużycie pamięci i f reprezentującą liczbę widełek dziecko) był 2p zamiast fp.

To rozwiązanie nie będzie działać w przypadku, gdy zużycie pamięci w postaci 2p nadal jest kosztem nie do zaakceptowania.

Dodano dwie optymalizacje: testy timeout/forceful-kill w przypadku upartych/zepsutych dzieci i warunkowe sleep s pomiędzy blokadami podrzędnymi, jeśli zamknięcie poprzedniego dziecka wymusiło rozpoczęcie wymiany przez system. sleep s dał systemowi czas na oddychanie/pobieranie stron z wymiany.

Ponownie, jest to optymalizacja problemu, a nie odpowiedź. Prawdziwą odpowiedzią jest @ ikegami.

Powiązane problemy