Linux używa COW, aby zmniejszyć zużycie pamięci po rozwidleniu, ale sposób, w jaki zmienne Perl 5 działają w perl
, zdaje się ominąć tę optymalizację. Na przykład, dla zmiennej:W jaki sposób mogę zapobiec uszkodzeniu pamięci podczas przetwarzania potomków przez zmienne metadane?
my $s = "1";
perl
jest naprawdę przechowywania:
SV = PV(0x100801068) at 0x1008272e8
REFCNT = 1
FLAGS = (POK,pPOK)
PV = 0x100201d50 "1"\0
CUR = 1
LEN = 16
Podczas korzystania z tego ciągu w kontekście numerycznym, to modyfikuje C struct
reprezentujący dane:
SV = PVIV(0x100821610) at 0x1008272e8
REFCNT = 1
FLAGS = (IOK,POK,pIOK,pPOK)
IV = 1
PV = 0x100201d50 "1"\0
CUR = 1
LEN = 16
Sam wskaźnik łańcucha nie zmienił się (nadal jest to 0x100201d50
), ale teraz jest w innym C struct
(a PVIV
zamiast PV
). Nie zmieniłem w ogóle wartości, ale nagle płacę koszt COW. Czy istnieje sposób na zablokowanie reprezentacji zmiennej Perl 5, tak aby oszczędzanie czasu (perl
nie musiało po raz drugi konwertować "0"
na 0
) nie rani mojego użycia pamięci?
Uwaga, reprezentacje powyżej zostały wygenerowane z tego kodu:
perl -MDevel::Peek -e '$s = "1"; Dump $s; $s + 0; Dump $s'
Dobrze, ale czy wiesz, co się stanie, gdy przydzielisz kilkaset MB danych, rozwiążesz kilka dzieci i że dzieci się skończą? GC i tak cię zabije. To smutna historia, ale Perl to niewłaściwe narzędzie do tego rodzaju pracy.Rozwiązaliśmy go częściowo, stosując podejście END {kill 9 $$}, ale w tym momencie powinieneś poszukać lepszego narzędzia ;-) –
GC mi nie przeszkadza, prawdziwy kod to 'mod_perl' i każde dziecko jest wielokrotnie używane . Problem polega na tym, że dane konfiguracyjne załadowane do rodzica są kopiowane do każdego z setek dzieci, mimo że dzieci nigdy go nie modyfikują (z punktu widzenia Perla 5, "perl" zawiera metadane). Drugim rozwiązaniem, które rozważałem, jest przeniesienie danych konfiguracyjnych do osobnego procesu i umożliwienie dzieciom rozmawiania z nimi przez gniazda domeny. –
Możesz także użyć pamięci współdzielonej, która będzie szybsza. –