얼마 전에 "리눅스 커널에 대한 심층적 이해"를 읽고 메모리 관리 부분에 대해 많은 시간을 보냈지만 아직 명확하지 않은 질문이 많이 있습니다. 최근에 시간을 들여 검토해 보았습니다. 여기에는 Linux의 메모리 관리에 대한 몇 가지 견해와 이해가 기록되어 있습니다.
나는 기술 자체의 개발 역사를 간단히 이해하는 것을 선호합니다. 이 기술이 어떻게 발전했는지, 이 기술 이전에는 어떤 기술이 존재했는지, 이러한 기술이 어떤 특성을 가지고 있는지, 현재의 기술로 대체되는 이유는 무엇입니까? 기술은 이전 기술의 문제를 해결합니다. 이를 이해하면 특정 기술을 더 명확하게 이해할 수 있습니다. 어떤 소재는 개발 과정이나 그 뒤에 숨은 원리를 언급하지 않은 채 특정 개념의 의미와 원리를 직접적으로 소개하는 경우도 있는데, 마치 기술이 하늘에서 떨어진 것처럼 말입니다. 이제 메모리 관리의 발전 역사를 바탕으로 오늘의 주제에 대해 이야기해보겠습니다.
우선 이 글의 주제가 리눅스 메모리 관리의 분할과 페이징 기술이라는 점을 먼저 설명드리고 싶습니다.
역사를 되돌아보겠습니다. 초기 컴퓨터에서는 프로그램이 물리적 메모리에서 직접 실행되었습니다. 즉, 실행 중 모든 프로그램 액세스는 물리적 주소입니다. 이 시스템이 하나의 프로그램만 실행한다면 이 프로그램에 필요한 메모리가 머신의 물리적 메모리를 초과하지 않는 한 문제가 없으며 어쨌든 번거로운 메모리 관리를 고려할 필요가 없습니다. 단지 당신의 프로그램, 그게 전부입니다. 돈을 절약하십시오. 충분히 먹을지 여부는 당신에게 달려 있습니다. 그러나 오늘날의 시스템은 멀티 태스킹 및 멀티 프로세싱을 지원하므로 CPU 및 기타 하드웨어의 활용도가 높아집니다. 이때 시스템의 제한된 물리적 메모리를 적시에 여러 프로그램에 할당하는 방법을 고려해야 합니다. 효과적인 방식으로, 이 문제 자체를 메모리 관리라고 합니다.
모든 사람의 이해를 돕기 위해 초기 컴퓨터 시스템의 메모리 할당 관리에 대한 예를 소개합니다.
프로그램 1, 2, 3의 세 가지 프로그램이 있습니다. 프로그램 1은 실행 중 10M 메모리가 필요하고, 프로그램 2는 실행 중 100M 메모리가 필요하며, 프로그램 3은 실행 중 20M 메모리가 필요합니다. 시스템이 프로그램 A와 B를 동시에 실행해야 하는 경우 초기 메모리 관리 프로세스는 아마도 첫 번째 10M의 물리적 메모리를 A에 할당하고 다음 10M-110M을 B에 할당하는 것과 같습니다. 이 메모리 관리 방법은 비교적 간단합니다. 지금 프로그램 C를 실행하려고 하고 시스템의 메모리가 128M에 불과하다고 가정해 보겠습니다. 분명히 이 방법에 따르면 프로그램 C는 부족하여 실행될 수 없습니다. 메모리. 가상 메모리 기술을 사용하면 메모리 공간이 부족할 때 프로그램에서 사용하지 않는 데이터를 디스크 공간으로 스왑할 수 있어 메모리 공간 확장이라는 목적을 달성했다는 것은 누구나 아는 사실이다. 이 메모리 관리 방법의 좀 더 명백한 문제를 살펴보겠습니다. 기사 시작 부분에서 언급했듯이 기술을 깊이 이해하려면 해당 기술의 개발 역사를 이해하는 것이 가장 좋습니다.
프로그램이 물리적 메모리에 직접 접근하기 때문에, 이때 프로그램이 사용하는 메모리 공간은 분리되지 않습니다. 예를 들어 위에서 언급한 것처럼 A의 주소 공간은 0~10M 범위에 있지만 A에 10M~128M 주소 공간의 데이터를 연산하는 코드가 있다면 프로그램 B와 프로그램 C는 충돌 가능성이 있습니다(모든 프로그램이 시스템의 전체 주소 공간을 차지할 수 있음). 이런 식으로 많은 악성 프로그램이나 트로이 목마 프로그램은 다른 프로그램을 쉽게 손상시킬 수 있으며, 시스템의 보안도 보장할 수 없어 사용자가 견딜 수 없습니다.
위에서 언급했듯이 프로그램 A, B, C를 동시에 실행하려면 가상 메모리 기술을 사용하여 일시적으로 사용되지 않는 일부 데이터를 쓰는 것이 유일한 방법입니다. 프로그램을 디스크에 저장한 다음 필요할 때 디스크에서 메모리로 다시 읽어옵니다. 프로그램 C는 20M의 메모리를 필요로 하고 A는 10M의 공간만 갖고 있으므로 프로그램 B를 디스크로 스왑해야 하기 때문에 당연히 불가능합니다. B는 완전히 100M입니다. 프로그램 C를 실행하려면 메모리에서 디스크로 100M의 데이터를 쓴 다음 프로그램 B를 실행해야 할 때 디스크에서 메모리로 읽어야 합니다. IO 작업에는 시간이 많이 걸리므로 이 프로세스의 효율성은 매우 낮습니다.
프로그램을 실행할 때마다 메모리에 충분히 큰 여유 공간을 할당해야 합니다. 문제는 이 여유 위치를 결정할 수 없다는 것입니다. 문제가 발생합니다. 재배치 문제는 프로그램에서 참조하는 변수 및 함수의 주소여야 합니다. 이해가 되지 않으면 컴파일 정보를 확인하면 됩니다.
메모리 관리는 위의 세 가지 문제를 해결하는 방법, 프로세스의 주소 공간을 격리하는 방법, 메모리 사용 효율성을 높이는 방법, 프로그램 실행 시 재배치 문제를 해결하는 방법에 지나지 않습니다.
검증할 수 없는 컴퓨터 업계의 명언은 다음과 같습니다. "컴퓨터 시스템의 모든 문제는 중간 계층을 도입하면 해결될 수 있습니다."
현재의 메모리 관리 방식에는 프로그램과 물리적 메모리 사이에 가상 메모리라는 개념이 도입되어 있습니다. 가상 메모리는 프로그램과 내부 메모리 사이에 위치합니다. 프로그램은 가상 메모리만 볼 수 있으며 더 이상 실제 메모리에 직접 접근할 수 없습니다. 각 프로그램은 자신만의 독립적인 프로세스 주소 공간을 갖고 있어 프로세스 격리를 달성합니다. 여기서 프로세스 주소 공간은 가상 주소를 의미합니다. 이름에서 알 수 있듯이 가상 주소이므로 실제 주소 공간이 아닌 가상 주소입니다.
프로그램과 물리적 주소 공간 사이에 가상 주소를 추가했기 때문에 프로그램은 결국 물리적 메모리에서 실행되어야 하고 주로 두 가지가 있기 때문에 가상 주소에서 물리적 주소로 매핑하는 방법을 찾아야 합니다. 유형: 분할 및 페이징 기술.
분할: 이 방법은 사람들이 사용하는 첫 번째 방법 중 하나입니다. 기본 아이디어는 프로그램에 필요한 메모리 주소 공간의 가상 공간을 특정 물리적 주소 공간에 매핑하는 것입니다.
세그먼트 매핑 메커니즘
각 프로그램에는 프로그램 A와 B의 가상 주소 공간이 모두 0x00000000에서 시작하는 독립적인 가상 독립 프로세스 주소 공간이 있습니다. 동일한 크기의 두 가상 주소 공간을 실제 물리적 주소 공간에 하나씩 매핑합니다. 즉, 가상 주소 공간의 각 바이트는 실제 주소 공간의 각 바이트에 해당합니다. 이 매핑 프로세스는 소프트웨어에 의해 설정됩니다. 실제 변환은 하드웨어에 의해 수행됩니다.
이 분할된 메커니즘은 기사 시작 부분에서 언급한 프로세스 주소 공간 격리 및 프로그램 주소 재배치라는 세 가지 문제를 해결합니다. 프로그램 A와 프로그램 B는 각각 독립적인 가상 주소 공간을 가지며, 가상 주소 공간은 서로 겹치지 않는 물리적 주소 공간에 매핑됩니다. 프로그램 A가 가상 주소 공간에 접근하는 주소가 0x00000000~0x00A00000 범위에 속하지 않는 경우 커널은 이 요청을 거부하므로 주소 공간 격리 문제를 해결합니다. 우리의 애플리케이션 A는 가상 주소 공간 0x00000000-0x00A00000에만 신경 쓰면 되고 어떤 물리적 주소에 매핑되는지 신경 쓸 필요가 없으므로 프로그램은 항상 재배치 없이 이 가상 주소 공간에 따라 변수와 코드를 배치합니다.
분할 메커니즘이 위의 두 가지 문제를 어떻게 해결하더라도 대단한 진전이지만 여전히 메모리 효율성 문제를 해결하지 못하고 있습니다. 이 메모리 매핑 메커니즘은 여전히 프로그램을 기반으로 하기 때문에 메모리가 부족하면 전체 프로그램을 디스크로 교체해야 하므로 메모리 사용 효율성은 여전히 매우 낮습니다. 그렇다면 효율적인 메모리 사용이란 무엇입니까? 실제로 프로그램의 로컬 작동 원리에 따르면 프로그램 실행 중 일정 기간 동안 데이터의 극히 일부만 자주 사용됩니다. 그래서 좀 더 세분화된 메모리 분할 및 매핑 방법이 필요합니다. 이때 Linux의 Buddy 알고리즘과 슬랩 메모리 할당 메커니즘을 생각해 보시겠습니까? 가상 주소를 물리적 주소로 변환하는 또 다른 방법은 페이징 메커니즘입니다.
페이징 메커니즘:
페이징 메커니즘은 메모리 주소 공간을 여러 개의 작은 고정 크기 페이지로 나누는 것입니다. Linux의 외부 파일 시스템이 디스크를 여러 블록으로 나누는 것과 마찬가지로 각 페이지의 크기는 메모리에 의해 결정됩니다. 이는 메모리와 디스크 활용도를 각각 향상시키기 위해 수행됩니다. 다음을 상상해 보세요. 디스크 공간을 N등분하여 각 부분(블록 1개)의 크기는 1M이고, 디스크에 저장하려는 파일이 1K바이트라면 나머지 999바이트는 낭비됩니다. 따라서 보다 세분화된 디스크 파티셔닝 방법이 필요합니다. 이는 물론 저장된 파일의 크기를 기준으로 한 것입니다. 페이징이라고 말하고 싶습니다. 메모리의 메커니즘은 ext와 다릅니다. 파일 시스템의 디스크 파티셔닝 메커니즘은 매우 유사합니다.
리눅스의 일반적인 페이지 크기는 4KB입니다. 프로세스의 주소 공간을 페이지별로 나누고, 자주 사용되는 데이터와 코드 페이지를 메모리에 로드하고, 덜 자주 사용되는 코드와 데이터를 디스크에 저장하는 예를 들어보겠습니다. .설명은 아래와 같습니다.
프로세스 가상 주소 공간, 물리적 주소 공간 및 디스크 간의 페이지 매핑 관계
프로세스 1과 프로세스 2의 가상 주소 공간이 불연속적인 물리적 주소로 매핑되는 것을 볼 수 있습니다. 공간(이것은 매우 중요합니다. 어느 날 연속적인 물리적 주소 공간이 충분하지 않지만 불연속적인 주소 공간이 많으면 이 기술이 없으면 프로그램을 실행할 수 없게 됩니다.) 또는 일부를 공유하는 경우에도 마찬가지입니다. 물리적 주소 공간의 공유 메모리입니다.
프로세스 1의 가상 페이지 VP2와 VP3이 디스크로 교체됩니다. 프로그램에 이 두 페이지가 필요할 때 Linux 커널은 페이지 오류 예외를 생성한 다음 예외 관리 프로그램이 이를 메모리로 읽습니다.
이것이 페이징 메커니즘의 원리입니다. 물론 Linux에서 페이징 메커니즘을 구현하는 것은 여전히 상대적으로 복잡합니다. 이는 전역 디렉터리, 상위 디렉터리, 페이지와 같은 여러 수준의 페이징 메커니즘을 통해 구현됩니다. 중간 디렉토리 및 페이지 테이블. 그러나 기본적으로 작동 원리는 변경되지 않습니다.
페이징 메커니즘을 구현하려면 하드웨어 구현이 필요합니다. 이 하드웨어의 이름은 MMU(Memory Management Unit)입니다. 특히 가상 주소를 물리적 주소로 변환하는 역할, 즉 가상 페이지에서 물리적 페이지를 찾는 역할을 합니다.
위 내용은 Linux의 메모리 관리에 대한 자세한 소개의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!