Teoretyczny model programisty na poziomie aplikacji sprawia, że wygląda tak. W rzeczywistości normalny proces uruchamiania (przynajmniej w Linuksie 1.x, wierzę, że 2.x i 3.x są zoptymalizowane, ale podobne) to:
- Kernel tworzy kontekst procesu (więcej lub nie-, maszyna wirtualna)
- do tej sytuacji procesowej, definiuje odwzorowanie wirtualnej pamięci, który mapuje z adresów pamięci RAM na początku swojego pliku wykonywalnego
- Zakładając, że jesteś dynamicznie powiązane (domyślnie/zwykły),
ld.so
program) zdefiniowany w nagłówkach programu konfiguruje mapowanie pamięci dla bibliotek współużytkowanych
- Jądro wykonuje
jmp
w procedurze uruchamiania twojego programu (dla programu C, to jest coś podobnego do crtprec80
, które wywołuje main
). Ponieważ tylko skonfigurował mapowanie i nie załadował żadnych stron (*), powoduje to błąd strony z jednostki zarządzania pamięcią procesora, która jest przerwaniem (wyjątkiem, sygnałem) jądra.
- Program obsługi błędów strony kernela ładuje część sekcji programu, w tym część , która spowodowała błąd strony, do pamięci RAM.
- Podczas pracy program uzyskuje dostęp do adresu wirtualnego, który nie ma kopii zapasowej pamięci RAM , wystąpią błędy strony i spowoduje, że jądro zawiesi program krótko, załaduje stronę z dysku, a następnie powrót kontroli do programu.To wszystko dzieje się "między instrukcjami" i jest zwykle niewykrywalne.
- Podczas korzystania z
malloc
/new
, jądro tworzy strony zapisu i zapisu RAM (bez plików kopii dysku) i dodaje je do wirtualnej przestrzeni adresowej.
- Jeśli rzucisz błąd strony, próbując uzyskać dostęp do lokalizacji pamięci, która nie jest skonfigurowana w mapowaniach pamięci wirtualnej, otrzymasz sygnał naruszenia segmentacji (SIGSEGV), który zwykle kończy się śmiercią.
- Gdy systemowi kończy się fizyczna pamięć RAM, strony pamięci RAM zostają usunięte; jeśli są to kopie tylko do odczytu z czegoś, co znajduje się już na dysku (jak plik wykonywalny lub plik obiektu współdzielonego), są one po prostu odrzucane i są ponownie ładowane ze źródła; jeśli są to dane do odczytu i zapisu (np. pamięć "utworzona" przy użyciu
malloc
), zostaną zapisane do pliku (page file = swap file = swap partition = na płycie wirtualnej). Uzyskanie dostępu do tych "zwalnianych" stron powoduje kolejny błąd strony i są one ponownie ładowane.
Zasadniczo, dopóki proces nie jest większy niż dostępna pamięć RAM - a dane są prawie zawsze znacznie większe niż pliki wykonywalne - można bezpiecznie udawać, że jesteś sam na świecie i żadne z tych żądań nie wymaga stronicowania wydarzenie.
Więc: skutecznie, jądro już jest uruchomiony program gdy jest on jednocześnie ładowany (a może nawet nigdy załadować kilka stron, jeśli nigdy nie wskoczyć do tego kodu/odnoszą się do tych danych).
Jeśli twój rozruch jest szczególnie powolny, możesz spojrzeć na system prelink
, aby zoptymalizować ładowanie bibliotek współdzielonych. Zmniejsza to ilość pracy, jaką musi wykonać ld.so
przy uruchamianiu (między exec
twojego programu i main
odbierania połączenia, jak również po pierwszym wywołaniu procedur bibliotecznych).
Czasami połączenie statyczne może poprawić wydajność programu, ale przy dużym koszcie pamięci RAM - ponieważ biblioteki nie są współużytkowane, duplikujesz "swój libc
" oprócz wspólnego libc
, że każdy inny program jest używając, na przykład. Jest to na ogół przydatne tylko w systemach wbudowanych, w których program działa mniej lub bardziej samodzielnie na komputerze.
(*) W rzeczywistości, jądro jest nieco mądrzejszy, i generalnie będzie przekręceniem niektórych stronach aby zmniejszyć liczbę błędów stron, ale teoria jest taka sama, niezależnie od optymalizacje
System operacyjny zazwyczaj radzi sobie z tym w rozsądny sposób. –
100 MB binarny niemożliwe? Mam tutaj 6MB binarny skompilowany z tylko 500 LOC, silnie szablony i program Boosted C++. Założę się, że mogłem to uderzyć do 100MB bez większych problemów. –
Nic nie jest niemożliwe! Po prostu skontaktuj się z wesołym programistą Eclipse, nauczą Cię wszystkich sztuczek. – Lundin