>운영 및 유지보수 >엔진스 >Linux 보호 모드의 메모리 관리

Linux 보호 모드의 메모리 관리

王林
王林앞으로
2023-07-06 15:20:031279검색

우리는 메모리가 매우 큰 배열로 간주될 수 있다는 것을 알고 있습니다. 메모리에서 요소를 찾으려면 배열의 첨자로 지정됩니다. 하지만 전제가 있습니다. 배열은 순서화된 바이트로 구성됩니다. 이 순서화된 바이트 배열에서 각 바이트는 고유한 주소를 갖습니다. 이 주소를 메모리 주소라고도 합니다.

메모리에는 많은 객체가 저장되어 있습니다. 각 객체는 char 객체, byte 객체, int 객체 등과 같이 서로 다른 바이트로 구성됩니다. 이들은 모두 메모리의 다양한 위치로 구분됩니다. 이러한 객체의 주소를 찾는 작업을 메모리 주소 지정이라고 합니다. 메모리 버스 폭은 주소 0부터 시작하여 주소 지정이 가능한 메모리 주소의 비트 수를 결정합니다. 80X86이 32비트이므로 버스 폭도 32비트이므로 총 2^32개의 메모리 주소가 있으므로 총 4GB의 메모리 주소를 저장할 수 있습니다. int, long, double 등의 다중 바이트 데이터 유형은 연속된 메모리 주소를 통해 추출될 수 있습니다.

객체는 주소를 지정할 수 있지만 이러한 객체가 저장되는 바이트 순서는 빅 엔디안과 리틀 엔디안이라는 두 가지 저장 방법이 있습니다.

예를 들어 주소 0x100에 int형 객체가 있고 그 값은 0x01234567입니다. 그림을 그려드리면 두 저장 순서의 차이를 이해하실 수 있을 것입니다.

Linux 保护模式下的内存管理

이것은 실제로 이해하기 쉽습니다. 0x01234567의 int 데이터 유형은 01 23 45 67바이트로 분할할 수 있으며 01은 상위 비트이고 67은 하위 비트이므로 리틀 엔디안의 저장 순서와 빅엔디안 방식으로 설명할 수 있다. 즉, 리틀엔디안 방식은 하위 비트를 먼저 사용하고, 빅엔디안 방식은 상위 비트를 먼저 사용한다. 빅엔디안과 리틀엔디안의 차이는 저장순서일 뿐, 객체의 자릿수나 수치와는 아무런 관련이 없습니다. 대부분의 Intel 시스템은 리틀 엔디안 모드를 사용하므로 80X86도 리틀 엔디안 스토리지인 반면, 대부분의 IBM 및 Oracle 시스템은 빅 엔디안 스토리지를 사용합니다.

메모리가 상대적으로 너무 크기 때문에 컴퓨터는 메모리에 있는 모든 데이터를 한 번에 직접 처리할 수 없기 때문에 일반적으로 메모리가 분할됩니다. 여기에는 메모리가 분할되는 이유가 무엇입니까? 위에서는 일반적인 소개를 했습니다.

왜 메모리를 분할해야 하나요?

https://www.php.cn/link/d005ce7aeef46bd18515f783fb8e87fa

세그먼테이션 메커니즘을 사용하여 메모리 공간을 선형 영역으로 나누고 각 선형 영역은 세그먼트 기본 주소와 세그먼트 내 주소로 찾을 수 있습니다. 오프셋. 세그먼트 기본 주소 부분은 16비트 세그먼트 선택기로 지정되며, 그 중 14비트는 2^14승, 즉 16384개의 세그먼트를 선택할 수 있으므로 세그먼트 내 오프셋 주소 부분은 32비트 값을 사용하여 지정됩니다. 세그먼트 내의 주소는 0 - 4G일 수 있으며, 세그먼트의 최대 길이는 4GB입니다. 이는 위에서 언급한 4GB 메모리 주소에 해당합니다. 16비트 세그먼트와 32비트 세그먼트 내의 오프셋으로 구성된 48비트 주소 또는 롱 포인터를 논리 주소라고 하며 논리 주소를 가상 주소라고 합니다.

X86 아키텍처에는 세그먼트 기본 주소를 저장하기 위한 6개의 특수 레지스터(CS, DS, ES, SS, FS 및 GS)가 있습니다. CS는 코드 세그먼트의 주소를 지정하는 데 사용되고 SS는 스택 세그먼트의 주소를 지정하는 데 사용되며 다른 레지스터는 데이터 세그먼트의 주소를 지정하는 데 사용됩니다. 주어진 순간에 CS에 의해 주소가 지정된 세그먼트를 현재 코드 세그먼트라고 합니다. 현재 코드 세그먼트에서 실행될 다음 명령어의 오프셋 주소가 EIP 레지스터에 이미 존재합니다. 이때 세그먼트 기본 주소:오프셋 주소는 CS:EIP로 표현될 수 있다.

세그먼트 레지스터 SS로 주소가 지정된 세그먼트를 현재 스택 세그먼트라고 합니다. 언제든지 ESP 레지스터가 스택의 상단을 가리키며 예외는 없습니다. 나머지 4개는 일반 데이터 세그먼트 레지스터입니다. 기본적으로 명령에 데이터 세그먼트가 없는 경우 DS에서 제공합니다.

주소 변환

일반적으로 완전한 메모리 관리 시스템은 액세스 보호와 주소 변환이라는 두 가지 구성 요소로 구성됩니다. 액세스 보호는 한 응용 프로그램이 다른 프로그램에서 사용하는 메모리 주소에 액세스하는 것을 방지하는 것입니다. 주소 변환은 다른 응용 프로그램에 동적 주소 할당 방법을 제공하는 것입니다. 액세스 보호와 주소 변환은 서로를 보완합니다.

주소 변환은 일반적으로 메모리 블록을 기본 단위로 사용합니다. 블록이 무엇인지에 대한 설명은 다음과 같습니다. Linux에서는 모든 것이 파일이고, 블록은 파일을 설명하는 데 사용됩니다. 시스템의 구성 단위는 데이터 처리의 기본 단위이기도 합니다. 공통 블록은 512B, 1KB, 4KB 등 크기가 다양합니다. 블록은 기본 단위이지만 본질적으로 섹터로 구성됩니다.

주소 변환을 구현하는 방법에는 분할 메커니즘과 페이징 메커니즘의 두 가지가 있습니다. x86의 메모리 관리 구현은 분할과 페이징 메커니즘을 결합합니다. 다음은 분할 및 페이징 후 물리적 주소로 변환된 가상 주소의 매핑 다이어그램입니다.

Linux 保护模式下的内存管理

이 그림에서는 설명이 필요합니다.

우선 이 그림에는 3개의 주소와 이 3개의 주소의 변환 프로세스가 포함되어 있습니다. 일반적으로 논리 주소는 분할된 기본 주소 변환 후 선형 주소가 됩니다. 선형 주소는 보호 모드 + 인트라 주소입니다. 세그먼트 오프셋이므로 이 그림은 보호 모드의 주소 변환 다이어그램입니다. 페이징 메커니즘을 활성화해야 하는 경우 선형 주소는 페이징 메커니즘 후에 물리적 주소로 변환됩니다. 페이징 메커니즘이 활성화되지 않은 경우 선형 주소 = 물리적 주소입니다.

논리 주소에 대해 다시 이야기해야겠습니다. 논리 주소에는 세그먼트 선택기와 세그먼트 내 오프셋이 포함되어 있습니다. 간단히 말해서 세그먼트 선택기의 개념은 비교적 모호합니다. 보호 모드에서는 세그먼트 기본 주소로 이해되므로 세그먼트 기본 주소는 16비트이고 세그먼트 내의 오프셋은 32비트라는 것을 모두 알고 있습니다.

많은 책이나 기사에서 세그먼트 선택자를 언급했습니다. 실제로 세그먼트 선택자는 번역의 문제입니다.

세그먼트 디스크립터에 대해서는 나중에 언급하겠습니다. 세그먼트 디스크립터와 세그먼트 선택기는 동일한 것이 아니지만 세그먼트 선택기는 16비트 세그먼트 디스크립터입니다.

이 그림에 나오지 않은 내용을 말씀드리자면, 이제 다들 논리 주소가 선형 주소로 변환될 수 있고, 선형 주소가 물리 주소로 변환될 수 있다는 사실을 알고 계실 것입니다. 그러면 근본 원인은 어떻게 변환됩니까? 실제로 여기서 사용되는 방법은 변환을 위해 MMU(메모리 관리 장치)이며 선형 주소를 물리적 주소로 변환하는 데는 페이징 장치의 하드웨어 회로가 사용됩니다. 이 기사의 초점은 특정 변환 프로세스를 논의하는 것이 아니라 분할과 페이징의 두 가지 메커니즘에 초점을 맞추는 것입니다.

세그먼테이션과 페이징의 두 가지 메커니즘에 대해 자세히 이야기해 보겠습니다.

Segmentation Mechanism

먼저 제가 "메모리를 분할해야 하는 이유"에 쓴 설명을 읽어보시길 권합니다.

https://www.php.cn/link/d005ce7aeef46bd18515f783fb8e87fa

여러 프로그램이 동일한 메모리 공간에서 실행되며 서로 간섭하지 않습니다. 이는 분할이 코드, 데이터 및 스택 메커니즘을 격리하기 때문입니다. . CPU에서 여러 개의 프로그램이나 작업이 실행 중인 경우 각 프로그램에는 자체 세그먼트 집합(프로그램 코드, 데이터 및 스택 포함)이 할당될 수 있습니다. 목적: CPU는 세그먼트 간의 경계를 강화하여 애플리케이션이 서로 간섭하는 것을 방지합니다.

시스템에서 사용되는 모든 세그먼트는 CPU의 선형 주소 공간에 포함됩니다. 지정된 세그먼트에서 바이트를 찾으려면 프로그램은 변환이 발생할 논리 주소를 제공해야 합니다. 논리 주소에는 세그먼트 선택기와 세그먼트 내의 오프셋이 포함됩니다. 각 세그먼트에는 세그먼트 설명자가 있으며 세그먼트 크기, 세그먼트의 액세스 권한 및 권한 수준, 세그먼트 유형 및 첫 번째 바이트를 나타내는 데 사용됩니다. 세그먼트의 위치는 성적 주소 공간(세그먼트 기본 주소)에 있습니다. 세그먼트에서 특정 바이트의 위치를 ​​찾기 위해 논리 주소의 오프셋 부분이 세그먼트 기본 주소에 추가되므로 세그먼트 기본 주소 + 오프셋이 CPU 선형 주소 공간에서 주소를 형성합니다.

선형 주소 공간은 물리적 주소 공간과 구조는 동일하지만 수용할 수 있는 세그먼트가 매우 다릅니다. 가상 주소, 즉 논리 주소 공간은 최대 16K 세그먼트를 포함할 수 있으며 각 세그먼트는 4GB이므로 가상 주소는 총 64TB(2^46) 세그먼트를 찾을 수 있으며 선형 주소와 물리적 주소 공간은 4GB(2^32)입니다. 따라서 페이징이 비활성화된 경우 선형 주소 공간은 물리적 주소 공간이 됩니다.

Linux 保护模式下的内存管理

이 그림은 논리 주소->선형 주소->물리적 주소의 매핑 다이어그램입니다. GDT 테이블과 LDT 테이블은 각각 ​​8192개의 세그먼트로 구성되어 있으며, 각 세그먼트는 위쪽에 있습니다. 4G까지 GDT 테이블에서 쿼리할지 LDT 테이블에서 쿼리할지는 세그먼트 선택기의 TI 속성에 따라 다릅니다. 세그먼트 선택기의 구조는 다음과 같습니다

Linux 保护模式下的内存管理

세그먼트 선택기는 다음과 같이 나뉩니다. 총 세 부분:

  • RPL(요청 권한 수준): 프로세스가 세그먼트에 액세스해야 하는 권한을 나타내는 요청 권한 수준입니다. 값이 클수록 권한은 작아집니다.
  • TI(테이블 표시기): 쿼리해야 하는 테이블을 나타냅니다. GDT 테이블을 쿼리하려면 TI = 0이고, LDT 테이블을 쿼리하려면 TI = 1입니다.
  • Index: CPU는 자동으로 Index * 8과 로드할 세그먼트 설명자인 GDT 및 LDT의 세그먼트 기본 주소를 추가합니다.

이 문서에서는 여전히 메모리 관리에 초점을 맞추고 특정 세부 사항에 너무 집착하지 않기 때문에 여기에는 세그먼트 설명자에 대한 자세한 설명이 없습니다.

GDTR에서는 세그먼트 선택자와 오프셋으로 구성된 논리 주소를 세그먼트 설명자로 합성하여 직접 저장할 수 있습니다. 세그먼트 선택기와 세그먼트 내 오프셋은 MMU를 통과한 후 선형 주소로 변환될 수 있습니다.

페이징 메커니즘

위에서 언급했듯이 선형 주소는 논리 주소에서 변환됩니다. 페이징 메커니즘이 비활성화된 경우 선형 주소는 물리적 주소입니다. 주소 공간은 여전히 ​​다릅니다. 일반적으로 프로그램은 멀티태스킹을 수행하며 일반적으로 멀티태스킹으로 정의되는 선형 주소 공간이 실제 메모리 용량보다 훨씬 큽니다. 주소 변환 맵을 보면 선형 주소와 물리적 주소 모두 크기가 4G임을 알 수 있습니다. 이는 선형 주소가 가상 스토리지 기술로 가상화되기 때문입니다.

가상 스토리지는 메모리 관리 기술입니다. 이 기술을 사용하면 메모리 공간이 실제 물리적 메모리 용량보다 훨씬 크다는 착각을 불러일으킬 수 있습니다. 그 본질은 메모리를 가상화하는 것입니다. 즉, 메모리는 4G일 수 있습니다. 그런데 메모리가 64G라고 생각하는데 왜 그렇게 많은 응용 프로그램을 열 수 있습니까?

페이징 메커니즘은 실제로 가상화된 환경에서 대량의 선형 주소 공간이 작은 물리적 메모리(RAM 또는 ROM)에 매핑됩니다. 페이징이 발생하면 각 세그먼트는 페이지(보통 4K)로 나뉘며, 이러한 페이지는 물리적 메모리나 디스크에 저장됩니다. 운영 체제는 페이지 디렉터리와 페이지 테이블을 사용하여 이러한 페이지를 유지 관리합니다. 프로그램이 선형 주소 공간의 주소 위치에 액세스하려고 시도하면 CPU는 페이지 디렉터리와 페이지 테이블을 사용하여 선형 주소를 물리적 주소로 변환한 다음 이를 물리적 메모리에 저장합니다.

현재 액세스한 페이지가 물리적 메모리에 없으면 CPU는 인터럽트를 실행합니다. 그러면 운영 체제는 하드 디스크의 페이지를 물리적 메모리로 읽은 다음 계속 실행합니다. 인터럽트 지점부터 프로그램을 실행합니다. 운영 체제는 종종 페이지를 자주 교체하고 이로 인해 성능 병목 현상이 발생합니다.

분할에서는 각 세그먼트의 길이가 고정되지 않으며, 페이징에서는 최대 길이가 4G로 각 페이지의 크기가 고정됩니다. 물리적 메모리에서든 디스크에서든 고정 크기 페이지를 사용하는 것이 물리적 메모리 관리에 더 적합한 반면, 가변 크기 블록을 사용하는 분할 메커니즘은 복잡한 시스템의 논리 파티션을 처리하는 데 더 적합합니다.

분할과 페이징은 서로 다른 두 가지 주소 변환 메커니즘이지만 전체 주소 변환 프로세스에서 독립적으로 처리되며 각 프로세스는 독립적입니다. 두 메커니즘 모두 중간 테이블을 사용하여 항목 매핑을 저장하지만 이 중간 테이블의 구조는 다릅니다. 세그먼트 테이블은 선형 주소 공간에 존재하고 페이지 테이블은 물리 주소 공간에 저장됩니다.

보호 메커니즘

80x86에는 두 가지 보호 메커니즘이 있으며, 그 중 하나는 각 작업에 서로 다른 가상 주소 공간을 할당하여 작업 간의 완전한 격리를 달성합니다. 이는 각 작업에 논리적 주소를 물리적 주소로 다르게 변환함으로써 달성됩니다. 각 애플리케이션은 자체 가상 공간의 데이터 및 명령에만 액세스할 수 있으며 자체 매핑을 통해서만 물리적 주소를 얻을 수 있습니다. 운영 체제의 메모리 세그먼트와 일부 특수 레지스터를 응용 프로그램이 액세스하지 못하도록 보호합니다. 아래에서 이 두 가지 작업에 대해 자세히 설명하겠습니다.

작업 간 보호

각 작업은 자체 가상 주소 공간에 별도로 배치된 다음 하드웨어를 통해 물리적 주소로 매핑되며, A의 가상 주소는 없습니다. 주소는 B가 위치한 물리적 주소 범위에 매핑되므로 모든 작업이 격리되고 서로 다른 작업이 서로 간섭하지 않습니다.

각 작업에는 자체 매핑 테이블, 세그먼트 테이블 및 페이지 테이블이 있습니다. CPU가 다른 애플리케이션이나 작업 간에 전환하면 이러한 테이블도 전환됩니다.

가상 주소는 운영 체제의 추상화입니다. 즉, 가상 주소는 애플리케이션과 작업을 더 잘 관리할 수 있는 캐리어로서 운영 체제에 의해 완전히 추상화됩니다. 각 작업은 논리 주소를 가상 주소로 매핑할 수 있습니다. 각 작업은 모든 작업이 공유하는 운영 체제에 액세스할 수 있음을 보여줍니다. 모든 작업이 동일한 가상 주소 공간을 갖는 가상 주소 공간의 이 부분을 전역 주소 공간이라고 하며 Linux는 전역 주소 공간을 사용합니다.

전역 주소 공간의 각 작업에는 고유한 가상 주소 공간이 있습니다. 이 가상 주소 공간을 로컬 주소 공간이라고 합니다.

메모리 세그먼트 및 레지스터의 특수 보호

다른 작업 간의 운영 체제 보호를 수평적 보호에 비유한다면 메모리 세그먼트 및 레지스터의 보호는 수직적 보호로 간주할 수 있습니다. 작업 내의 다양한 세그먼트에 대한 액세스를 제한하기 위해 운영 체제는 각 작업을 보호하기 위해 네 가지 권한 수준을 설정합니다.

우선순위는 4단계로 나뉘는데, 0이 가장 높고 3이 가장 낮습니다. 일반적으로 가장 민감한 데이터에는 가장 높은 우선순위가 부여되며 작업에서 가장 신뢰할 수 있는 부분에서만 액세스할 수 있습니다. 덜 민감한 데이터에는 일반적으로 낮은 우선순위가 부여되며 애플리케이션 데이터는 레벨 0입니다. 일반적으로 레벨 3. 각 메모리 세그먼트는 권한 수준과 연관되어 있습니다.

CPU는 실행을 위해 CS를 통해 세그먼트에서 명령과 데이터를 얻는다는 것을 알고 있습니다. 세그먼트에서 얻은 명령과 데이터는 일반적으로 현재 권한 수준(CPL)으로 액세스됩니다. 현재 활성 코드의 수준입니다. 애플리케이션이 세그먼트에 접근을 시도할 때, 이 권한 수준과 비교되어, 이 세그먼트보다 낮은 권한 수준만 접근이 가능합니다.

위 내용은 Linux 보호 모드의 메모리 관리의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
이 기사는 51cto.com에서 복제됩니다. 침해가 있는 경우 admin@php.cn으로 문의하시기 바랍니다. 삭제