Całość stanowi fork()realizowany jest za pomocą mmap / kopiowania przy zapisie.
Wpływa to nie tylko na stertę, ale także na biblioteki współdzielone, stos, obszary BSS.
Co, nawiasem mówiąc, oznacza, że rozwidlenie jest niezwykle lekką operacją, dopóki wynikowe 2 procesy (nadrzędny i podrzędny) faktycznie nie zaczną zapisywać w zakresach pamięci. Ta funkcja w znacznym stopniu przyczynia się do niszczenia bomb widelcowych - kończy się zbyt wiele procesów, zanim jądro zostanie przeciążone replikacją i różnicowaniem stron.
Trudno będzie znaleźć w nowoczesnym systemie operacyjnym przykład operacji, w której jądro wykonuje kopię drukowaną (wyjątek stanowią sterowniki urządzeń) - po prostu znacznie, znacznie łatwiej i wydajniej jest korzystać z funkcji VM.
Nawet execve()jest w zasadzie „prosze mapować plik binarny / ld.so / whatnot, a następnie wykonać” - a VM obsługuje faktyczne ładowanie procesu do pamięci RAM i wykonywanie. Lokalne niezainicjowane zmienne są w końcu kształtowane na „stronie zerowej” - specjalna strona tylko do odczytu, która zawiera zera, lokalne zmienne inicjalizowane są w końcu kształtowane (ponownie kopiowanie podczas zapisu, ponownie) z samego pliku binarnego, itp.
Jednym godnym uwagi wyjątkiem są procesy Java. Wyszukaj „rozwidlenie pamięci Java”, a znajdziesz dziesiątki problemów wpływających na JVM dużego serwera lub osadzoną JVM próbujących wykonać małe polecenie powłoki i niefortunnie zawieszających się w wyjątku „Nie można przydzielić pamięci” (są to tylko losowe łącza, ten problem ma charakter systemowy do środowisk Java). Ta odpowiedź SO oskarża moduł zbierający śmieci JVM i kompilator JIT o powstrzymywanie udostępniania pamięci procesów.
WhiteWinterWolf
24
Jądro Linux implementuje funkcję Copy-on-Write, gdy fork()jest wywoływana. Po uruchomieniu syscall strony udostępnione przez rodzica i dziecko są oznaczone jako tylko do odczytu.
Jeśli zapis jest wykonywany na stronie tylko do odczytu, jest on następnie kopiowany, ponieważ pamięć nie jest już identyczna między dwoma procesami. Dlatego, jeśli wykonywane są tylko operacje odczytu, strony w ogóle nie zostaną skopiowane.
+1 dzięki! 1. Czy możesz podać linki referencyjne? 2. Czy kupa jest kopiowana w całości lub w części?
Adam Matan
4
2. - Na stronach :) Jądro bardzo mało rozumie, czym jest „sterta” - dla jądra jest to tylko garstka zmapowanych prywatnych stron, które alokatorzy libc potrafią obsłużyć.
qdot
Czy to naprawdę bomba widełkowa? Wydaje mi się, że zamiast rozwidlać bieżący proces, kod ten utworzy więcej instancji tego samego programu, które wykonują się od początku, niż od następnej instrukcji po fork()wywołaniu.
sherrellbc
@mmk FYI, byłem dość zaskoczony twoją „Ciekawą notatką:”, więc przetestowałem (na Linuksie 3.2.0), aby zobaczyć i nie wydaje się to prawdą. Kiedyś /proc/self/pagemapokreślałem adres wirtualny do fizycznego mapowania strony na potrzeby testu. Tak jak się spodziewałem, jeśli wnuk i tylko wnuczek pisze udostępnioną stronę, to rodzic i pierwotne dziecko nadal ją udostępniają. Tylko wnuk kończy się na prywatnej kopii.
Celada,
@Celada. Hmm Przeczytałem to gdzieś i nie pamiętam wersji jądra, do której się odnosił (prawdopodobnie starszej?), Więc może już nie być poprawna.
mmk
10
Linux wykonuje kopiowanie przy zapisie. W miarę forktworzenia nowego procesu przydzielone strony są oznaczane jako tylko do odczytu i udostępniane między rodzicem a dzieckiem. Gdy którakolwiek z nich próbuje zmodyfikować stronę, generowany jest błąd strony, który powoduje skopiowanie strony i odpowiednie dostosowanie tabeli stron.
Jądro Linux implementuje funkcję Copy-on-Write, gdy
fork()
jest wywoływana. Po uruchomieniu syscall strony udostępnione przez rodzica i dziecko są oznaczone jako tylko do odczytu.Jeśli zapis jest wykonywany na stronie tylko do odczytu, jest on następnie kopiowany, ponieważ pamięć nie jest już identyczna między dwoma procesami. Dlatego, jeśli wykonywane są tylko operacje odczytu, strony w ogóle nie zostaną skopiowane.
źródło
fork()
wywołaniu./proc/self/pagemap
określałem adres wirtualny do fizycznego mapowania strony na potrzeby testu. Tak jak się spodziewałem, jeśli wnuk i tylko wnuczek pisze udostępnioną stronę, to rodzic i pierwotne dziecko nadal ją udostępniają. Tylko wnuk kończy się na prywatnej kopii.Linux wykonuje kopiowanie przy zapisie. W miarę
fork
tworzenia nowego procesu przydzielone strony są oznaczane jako tylko do odczytu i udostępniane między rodzicem a dzieckiem. Gdy którakolwiek z nich próbuje zmodyfikować stronę, generowany jest błąd strony, który powoduje skopiowanie strony i odpowiednie dostosowanie tabeli stron.źródło