To jest stary post, jednak nadal chciałbym się tutaj wypowiedzieć.
Począwszy od dołu, Linux najpierw dzielił pamięć na strony (zwykle 4K na stronę w systemie x86_64). Następnie tworzona jest pamięć wirtualna, której mapowanie odbywa się za pomocą pamięci fizycznej za pomocą MMU (Memory Management Unit).
Procesom przydzielana jest pamięć z obszaru pamięci wirtualnej, więc pamiętaj, że gdy zobaczysz / proc / meminfo, zobaczysz VMalloc * jako szczegóły pamięci wirtualnej.
Powiedzmy, że masz proces, który żąda pamięci (powiedzmy 300 MB - przeglądarka internetowa). Proces zostanie przydzielony 300 MB z pamięci wirtualnej, jednak nie jest konieczne mapowanie pamięci (która jest mapowana na pamięć fizyczną). Istnieje koncepcja „Kopiuj przy zapisie” do zarządzania pamięcią, zgodnie z którą, jeśli twoje procesy faktycznie korzystają z pamięci przydzielonej z pamięci wirtualnej (to znaczy, że zapisuje w pamięci), tylko wtedy jest mapowane na pamięć fizyczną. Pomaga to jądrze poprawnie działać w środowisku wieloprocesowym.
Co to jest pamięć podręczna?
Wiele pamięci wykorzystywanej przez procesy jest współdzielone. Powiedzmy, że biblioteka glibc jest używana przez prawie wszystkie procesy. Jaki jest sens przechowywania wielu kopii glibc w pamięci, kiedy każdy proces może uzyskać dostęp do tej samej lokalizacji w pamięci i wykonać zadanie. Tak często używane zasoby są przechowywane w pamięci podręcznej, dzięki czemu, gdy procesy wymagają, można je odnieść do tej samej lokalizacji pamięci. Pomaga to w przyspieszeniu procesów, ponieważ ponowne czytanie glibc (itp.) Z dysku byłoby czasochłonne.
Powyższe dotyczyło bibliotek współdzielonych, powiedzmy, podobnie jest również w przypadku odczytu plików. Jeśli po raz pierwszy przeczytasz duży plik (powiedzmy 100-200 MB), zajmie to dużo czasu. Gdy jednak spróbujesz powtórzyć ten sam odczyt, będzie to szybsze. Dane były buforowane w pamięci, a ponowne odczytanie nie zostało wykonane dla wszystkich bloków.
Co to jest bufor?
Jeśli chodzi o bufor, gdy proces wykonuje operacje we / wy pliku, polega na buforze jądra do zapisywania danych na dysku. Procesy żądają od jądra wykonania zadania. Zatem w imieniu procesu jądro zapisuje dane do swojego „bufora” i informuje proces, że zapis został zakończony. W asynchroniczny sposób jądro będzie synchronizowało te dane w buforze na dysk. W ten sposób procesy polegają na tym, że jądro wybiera właściwy czas do zsynchronizowania danych na dysk, a procesy mogą dalej działać. Pamiętaj, że są to ogólne operacje we / wy wykonywane przez normalne procesy. Jednak wyspecjalizowane procesy, które muszą potwierdzić, że operacje we / wy są faktycznie wykonywane na dysku, mogą używać innego mechanizmu do wykonywania operacji we / wy na dysku. Niektóre narzędzia Open Source to Libaio. Istnieją również sposoby na wywołanie jawnej synchronizacji z FD otwartymi w kontekście procesów,
Jakie są zatem błędy strony?
Rozważ przykład, kiedy zaczynasz proces (powiedzmy przeglądarkę internetową), którego plik binarny ma około 300 MB. Jednak pełne 300 MB pliku binarnego przeglądarki internetowej nie zaczyna działać natychmiast. Proces przechodzi od funkcji do funkcji w kodzie. Jak powiedziano wcześniej, pamięć wirtualna zostałaby zużyta 300 MB, jednak nie cała pamięć jest mapowana na pamięć fizyczną (pamięć rezydentna RSS byłaby mniejsza, patrz górne wyjście). Gdy wykonanie kodu osiągnie punkt, dla którego pamięć nie jest faktycznie odwzorowana fizycznie, wystąpią błędy strony. Jądro zamapuje tę pamięć na fizyczną, skojarzy stronę pamięci z procesem. Taki błąd strony nazywa się „drobnymi błędami strony”. Podobnie mówiąc, gdy proces wykonuje operacje we / wy pliku, zgłaszane są poważne błędy strony.
Kiedy i dlaczego następuje zamiana?
Sytuacja 1:
Zgodnie z powyższymi szczegółami rozważmy scenariusz, w którym znaczna ilość pamięci zostaje zmapowana. A teraz uruchamia się proces, który wymaga pamięci. Jak omówiono powyżej, jądro będzie miało pewne mapowanie pamięci. Jednak nie ma wystarczającej ilości fizycznej pamięci RAM, aby zmapować pamięć. Teraz jądro najpierw zajrzy do pamięci podręcznej, będzie miało kilka starych stron pamięci, które nie są używane. Opróżni te strony na osobnej partycji (zwanej SWAP), zwolni niektóre strony i zamapuje zwolnione strony na nadchodzące nowe żądanie. Ponieważ zapis na dysku jest znacznie wolniejszy niż półprzewodnikowa pamięć RAM, proces ten zajmuje dużo czasu i dlatego następuje spowolnienie.
Sytuacja 2:
Powiedzmy, że widzisz dużo wolnej pamięci dostępnej w systemie. Nawet wtedy widać, że dzieje się wiele wymian. Może występować prawdopodobny problem fragmentacji pamięci. Rozważ procesy, które wymagają 50 MB ciągłej pamięci z jądra. (pamiętaj o ciągłym). Oczywiście jądro przydzieliłoby strony losowo do różnych procesów i uwolniło niektóre z nich. Jednak gdy wymagamy ciągłej pamięci, będzie ona musiała szukać fragmentu, który zaspokoi zapotrzebowanie na procesy. Jeśli nie będzie w stanie uzyskać takiej pamięci, będzie musiał zamienić niektóre stare strony pamięci, a następnie przydzielić ciągłe. Nawet w takich przypadkach nastąpi zamiana. Począwszy od jądra w wersji 2.6 i wyżej, problemy z fragmentacją znacznie się zmniejszyły. Jednak jeśli system działa przez długi czas, takie problemy mogą się pojawić.
Zobacz ten przykład ( wyjście vmstat )
2016-10-29 03:55:32 procs -----------memory---------- ---swap-- -----io---- --system-- -----cpu------
2016-10-29 03:55:32 r b swpd free buff cache si so bi bo in cs us sy id wa st
2016-10-30 03:56:04 19 23 2914752 4692144 3344908 12162628 1660 1 8803 12701 4336 37487 14 7 40 38 0
2016-10-30 03:56:34 3 20 2889296 4977580 3345316 12026752 2109 2 8445 14665 4656 36294 12 7 46 34 0
2016-10-30 03:57:04 1 11 3418868 4939716 3347804 11536356 586 4744 2547 9535 3086 24450 6 3 59 33 0 <<<-----
2016-10-30 03:57:34 3 19 3456252 5449884 3348400 11489728 3291 13371 6407 17957 2997 22556 6 4 66 24 0
2016-10-30 03:58:04 7 6 4194500 5663580 3349552 10857424 2407 12240 3824 14560 2295 18237 4 2 65 29 0
2016-10-30 03:58:34 2 16 4203036 5986864 3348908 10838492 4601 16639 7219 18808 2575 21563 6 4 60 31 0
2016-10-30 03:59:04 3 14 4205652 6059196 3348760 10821448 6624 1597 9431 4357 1750 20471 6 2 60 31 0
2016-10-30 03:59:34 2 24 4206968 6053160 3348876 10777216 5221 2067 10106 7377 1731 19161 3 3 62 32 0
2016-10-30 04:00:04 0 13 4205172 6005084 3348932 10785896 6236 1609 10330 6264 1739 20348 4 2 67 26 0
2016-10-30 04:00:34 4 11 4206420 5996396 3348976 10770220 6554 1253 10382 4896 1964 42981 10 5 58 27 0
2016-10-30 04:01:04 6 4 4177176 5878852 3348988 10825840 8682 765 10126 2716 1731 32949 8 4 69 19 0
@ 2016-10-30 03:57:04, widzimy, że wciąż jest dostępna duża ilość wolnej pamięci RAM. Jednak nawet wtedy nastąpiła zamiana. W tym momencie sprawdziliśmy drzewo procesów i nie widzieliśmy żadnego procesu, który wymagałby tak dużej ilości pamięci (więcej niż wolna pamięć). Oczywistym podejrzeniem była sytuacja 2 opisana powyżej. Sprawdziliśmy dzienniki buddyinfo i zoneinfo powyżej (użyj echo m> / proc / sysrq-trigger, aby to sprawdzić, dane wyjściowe trafiają do syslogs).
W przypadku naszego normalnego systemu porównanie informacji o strefie wygląda tak. A wykresy dla pamięci podręcznej / wolnej / niskiej pamięci są również wymienione poniżej
Patrząc na informacje, jasne jest, że fragmentacja pamięci w węźle 0 i węźle 1 jest normalna (węzeł jest maszyną opartą na NUMA, stąd wiele węzłów (patrz numactl, aby sprawdzić informacje dla twojego systemu)).
Fragmentacja pamięci jest również powodem, dla którego użycie wymiany może wzrosnąć, nawet jeśli dostępna jest wolna pamięć.