2011-12-14 8 views
10

Czy kopiuje cały plik binarny do pamięci, zanim zostanie wykonany? Jestem zainteresowany tym pytaniem i chcę go zmienić na inny sposób. Mam na myśli, że jeśli binaria ma 100M duży (wydaje się niemożliwe), mógłbym go uruchomić, podczas gdy kopiuję go do pamięci. Czy to możliwe?Kiedy działa plik binarny, czy kopiuje on wszystkie dane binarne do pamięci jednocześnie? Czy mogę to zmienić?

Czy możesz mi powiedzieć, jak wyświetlić sposób, w jaki działa? Jakie narzędzia są potrzebne?

+3

System operacyjny zazwyczaj radzi sobie z tym w rozsądny sposób. –

+1

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. –

+3

Nic nie jest niemożliwe! Po prostu skontaktuj się z wesołym programistą Eclipse, nauczą Cię wszystkich sztuczek. – Lundin

Odpowiedz

24

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

+0

Mam wrażenie, że zapomniałeś relokatora, który musi przejechać blok wykonalny załadowany do pamięci (http://en.wikipedia.org/wiki/Relocation_%28computer_science%29). O ile mi wiadomo, dzieje się to tylko raz podczas ładowania kodu i nie jestem pewien, czy program obsługi "strony-usterki" po prostu uruchomi ten algorytm "relokatora", podczas gdy program już działa. Tak więc, moim zdaniem, przynajmniej jeden wykonywalny blok musi zostać wczytany przed rozpoczęciem egzekucji. Ale nie jestem ekspertem od "linux-loader" ... – LittleFunnyMan

+2

Ja * wierzę * to wszystko jest obsługiwane przez 'ld.so' na Linuksie, ale nie mam tendencji do wtrącania się w sprawy magów :-) ... Jest też dużo czarnej magii zaangażowanych w operacje' thunk' i takie, zdarza się to po raz pierwszy w wywołaniu procedury bibliotecznej ... – BRFennPocock

+0

Zobacz http://em386.blogspot.com/2006/10/resolving-elf-relocation-name-symbols.html, aby dowiedzieć się, jak działa przeniesienie. –

6

Nie, tylko ładuje niezbędne strony do pamięci. To jest stronicowanie na żądanie.

Nie wiem o narzędziu, które może naprawdę pokazać, że w czasie rzeczywistym, ale można spojrzeć na /proc/xxx/maps, gdzie xxx jest PID procesu.

+0

W Gnome Monitor systemu wyświetli mapy pamięci. Aplikacje/Narzędzia systemowe/Monitor systemu → zakładka Procesy → kliknij prawym przyciskiem myszy proces → Mapy pamięci. Okno często pojawia się puste po otwarciu, ponieważ paski przewijania są ustawione niezgrabnie, więc sprawdź je, jeśli uważasz, że masz pusty wyświetlacz :-) – BRFennPocock

2

Podczas zadawania prawidłowego pytania, nie sądzę, że jest to coś, o co należy się martwić. Po pierwsze, plik binarny o wartości 100M nie jest niemożliwy. Po drugie, program ładujący system załaduje potrzebne strony z ELF (format wykonywalny i możliwy do połączenia) do pamięci i wykona różne przeniesienia itp., Które spowodują jego działanie, jeśli będzie to konieczne. W ten sam sposób załaduje również wszystkie wymagane biblioteki współdzielone. Nie jest to jednak czasochłonny proces, który nie wymaga optymalizacji. Prawdopodobnie każda "optymalizacja" miałaby znaczny narzut, aby upewnić się, że nie próbuje użyć czegoś, co nie zostało załadowane we właściwym czasie i prawdopodobnie byłaby wydajna.

Jeśli jesteś ciekawy, co jest mapowane, jak mówi fge, możesz sprawdzić/proc/pid/maps. Jeśli chcesz zobaczyć, jak mnóstwo programów, można spróbować uruchomić program z strace, jak:

strace ls 

To dość rozwlekły, ale powinno dać pewne wyobrażenie o mmap() wywołuje itp

Powiązane problemy