Komendy , na przykład sed
, są programami, a programy są zakodowaną logiką w pliku i pliki te znajdują się gdzieś na dysku twardym. Jednak podczas wykonywania poleceń kopia ich plików z dysku twardego jest umieszczana w pamięci RAM , gdzie ożywają i mogą wykonywać różne czynności oraz są nazywane procesami .
Procesy mogą wykorzystywać inne pliki, odczytywać je lub zapisywać, a jeśli tak, to pliki te nazywane są plikami otwartymi. Jest to polecenie, aby wyświetlić listę wszystkich otwartych plików przez wszystkich uruchomionych procesów: lsof
.
OK, więc zastanawiam się, czy podwójne życie polecenia, jednego na dysku twardym, drugiego w pamięci RAM, dotyczy również innych rodzajów plików, na przykład tych, które nie mają zaprogramowanej logiki, ale są po prostu pojemnikami na dane.
Zakładam, że pliki otwierane przez procesy są również ładowane do pamięci RAM. Nie wiem, czy to prawda, to tylko intuicja.
Czy ktoś mógłby to zrozumieć?
Odpowiedzi:
To jest złe (ogólnie). Kiedy program jest wykonywany (przez execve (2) ...), proces (uruchamiający ten program) zmienia swoją wirtualną przestrzeń adresową i jądro ponownie konfiguruje MMU w tym celu. Przeczytaj także o pamięci wirtualnej . Zauważ, że aplikacje mogą zmieniać swoją wirtualną przestrzeń adresową za pomocą mmap (2) i
munmap
& mprotect (2) , również używanych przez dynamiczny linker (patrz ld-linux (8) ). Zobacz także madvise (2) i posix_fadvise (2) i mlock (2) .Błędy przyszłej strony będą przetwarzane przez jądro w celu ładowania (leniwie) stron z pliku wykonywalnego. Przeczytaj także o thrashingu .
Jądro utrzymuje dużą pamięć podręczną stron . Przeczytaj także o kopiowaniu przy zapisie . Zobacz także readahead (2) .
W przypadku wywołań systemowych, takich jak read (2) i write (2), używana jest również pamięć podręczna stron. Jeśli dane, które mają zostać odczytane, znajdują się w nim, nie zostanie wykonane IO dysku. Jeśli potrzebne jest IO dysku, odczytane dane najprawdopodobniej zostaną umieszczone w pamięci podręcznej strony. Tak więc w praktyce, jeśli uruchomisz to samo polecenie dwa razy, może się zdarzyć, że po raz drugi na dysku nie zostaną wykonane fizyczne operacje we / wy (jeśli masz stary obrotowy dysk twardy - nie dysk SSD), możesz to usłyszeć; lub uważnie obserwuj diodę dysku twardego).
Polecam lekturę książki takiej jak Systemy operacyjne: trzy łatwe utwory (do pobrania za darmo, jeden plik PDF na rozdział), która wyjaśnia to wszystko.
Zobacz także Linux Ate My RAM i wykonywania poleceń jak
xosview
,top
,htop
lubcat /proc/self/maps
lubcat /proc/$$/maps
(patrz proc (5) ).PS. Skupiam się na Linuksie, ale inne systemy operacyjne mają również pamięć wirtualną i pamięć podręczną stron.
źródło
Nie, plik nie jest automatycznie wczytywany do pamięci przez jego otwarcie. To byłoby okropnie nieefektywne.
sed
, na przykład, czyta swoje wejście wiersz po wierszu, podobnie jak wiele innych narzędzi uniksowych. Rzadko musi utrzymywać w pamięci więcej niż bieżący wiersz.Z
awk
tym samym. Odczytuje rekord naraz, który domyślnie jest linią. Jeśli przechowujesz części danych wejściowych w zmiennych, będzie to dodatkowe, oczywiście 1 .Niektórzy ludzie mają zwyczaj robienia takich rzeczy
Ponieważ powłoka będzie musiała
$(cat file)
całkowicie rozszerzyć podstawianie poleceń przed uruchomieniem nawet pierwszej iteracjifor
pętli, spowoduje to odczytanie całejfile
pamięci (do pamięci używanej przez powłokę wykonującąfor
pętlę). To jest trochę głupie, a także nieeleganckie. Zamiast tego należy zrobićSpowoduje to przetworzenie
file
linia po linii (ale należy przeczytać Zrozumienie „IFS = czytaj -r linia” ).Przetwarzanie plików wiersz po wierszu w powłoce jest jednak rzadko potrzebne, ponieważ większość narzędzi i tak jest zorientowana liniowo (zobacz Dlaczego używanie pętli powłoki do przetwarzania tekstu jest uważane za złą praktykę? ).
Pracuję w bioinformatyce, a kiedy przetwarzam ogromne ilości danych genomowych, nie byłbym w stanie wiele zrobić, chyba że zachowałem tylko te fragmenty danych, które były absolutnie niezbędne w pamięci. Na przykład, gdy muszę usunąć fragmenty danych, które mogłyby zostać wykorzystane do identyfikacji osób z 1-terabajtowego zestawu danych zawierającego warianty DNA w pliku VCF (ponieważ tego typu danych nie można upublicznić), wykonuję wiersz po wierszu przetwarzanie za pomocą prostego
awk
programu (jest to możliwe, ponieważ format VCF jest zorientowany liniowo). I nie odczytać pliku do pamięci, przetworzyć go tam, i ponownie je zapisze się ponownie! Gdyby plik został skompresowany, przekazałbym gozcat
lubgzip -d -c
, ponieważ ponieważgzip
przetwarza przetwarzanie danych w strumieniu, również nie odczytałby całego pliku do pamięci.Nawet w przypadku formatów plików, które nie są zorientowane liniowo, takich jak JSON lub XML, istnieją parsery strumieniowe, które umożliwiają przetwarzanie dużych plików bez przechowywania ich w pamięci RAM.
W przypadku plików wykonywalnych jest to nieco bardziej skomplikowane, ponieważ biblioteki współdzielone mogą być ładowane na żądanie i / lub dzielone między procesami ( na przykład Ładowanie bibliotek współdzielonych i użycie pamięci RAM ).
Buforowanie to coś, o czym tu nie wspomniałem. Jest to działanie polegające na użyciu pamięci RAM do przechowywania często używanych fragmentów danych. Mniejsze pliki (na przykład pliki wykonywalne) mogą być buforowane przez system operacyjny w nadziei, że użytkownik dokona wielu odwołań do nich. Oprócz pierwszego odczytu pliku, kolejne dostępy będą miały miejsce w pamięci RAM, a nie na dysku. Buforowanie, podobnie jak buforowanie danych wejściowych i wyjściowych, jest zwykle w dużej mierze przezroczyste dla użytkownika, a ilość pamięci używanej do buforowania rzeczy może się dynamicznie zmieniać w zależności od ilości pamięci RAM przydzielonej przez aplikacje itp.
1 Technicznie rzecz biorąc, większość programów prawdopodobnie odczytuje fragment danych wejściowych naraz, albo za pomocą buforowania jawnego, albo pośrednio przez buforowanie, które robią standardowe biblioteki we / wy, a następnie przedstawia ten fragment linia po linii do kodu użytkownika. O wiele bardziej efektywne jest odczytywanie wielokrotności rozmiaru bloku dysku niż np. Znak na raz. Jednak ten rozmiar fragmentu rzadko jest większy niż garść kilobajtów.
źródło
awk
,{ a[i++] = $0 }
by dodać wszystkie linie pliku wejściowego do tablicya
. Możesz także sprawdzić funkcję Cmmap()
, ale jej użycie może być nieco nie na temat.sed
,awk
i inne programy zorientowane liniowo nie odczytują linii do pamięci na raz, ponieważ zwykłe pliki tekstowe nie zawierają indeksu linii, a interfejsy API systemu plików i sprzęt pamięci masowej niskiego poziomu odczytują jeden lub więcej „sektorów” (zwykle 512 lub 1024 bajty) na raz. Byłbym zaskoczony, gdyby system operacyjny wczytał mniej niż 8 KB do pamięci przed przetworzeniem pierwszego wiersza.sed
odczytuje do pamięci tylko jedną linię na raz, warto wspomnieć, że system operacyjny użyje wolnego pamięci RAM do buforowania plików, aby umożliwić szybki dostęp do nich. Jeśli używaszsed
mniejszego pliku, możliwe jest, że system operacyjny zbuforuje cały plik w pamięci, a operacja zostanie wykonana całkowicie w pamięci RAM. Zobacz: en.wikipedia.org/wiki/Page_cacheNie. Podczas gdy występy pamięci RAM są fantastyczne, był czas, kiedy pamięć RAM była bardzo ograniczonym zasobem (nauczyłem się programowania na VAX 11/750 z 2 MB pamięci RAM), a jedyną rzeczą w pamięci RAM była aktywna strona wykonywalna i strony danych aktywnych procesów i danych plików znajdujących się w pamięci podręcznej bufora.
Pamięć podręczna bufora została opróżniona, a strony danych zostały zamienione. I często czasami. Strony wykonywalne tylko do odczytu zostały nadpisane, a tablice stron zaznaczone, więc jeśli program dotknie tych stron ponownie, zostaną umieszczone w systemie plików. Dane zostały przywołane z wymiany. Jak wspomniano powyżej, biblioteka STDIO pobierała dane w blokach i były uzyskiwane przez program w razie potrzeby: fgetc, fgets, fread itp. Przy pomocy mmap plik można mapować na przestrzeń adresową procesu, tak jak to robi się z współdzielone obiekty biblioteki lub nawet zwykłe pliki. Tak, możesz mieć pewien stopień kontroli, jeśli jest w pamięci RAM lub nie (mlock), ale idzie tylko tak daleko (patrz sekcja kodu błędu w mlock).
źródło