> 운영 및 유지보수 > 리눅스 운영 및 유지 관리 > 가상 메모리 관리에 대한 자세한 설명

가상 메모리 관리에 대한 자세한 설명

PHP中文网
풀어 주다: 2017-06-20 11:23:26
원래의
3592명이 탐색했습니다.

  최신 운영 체제는 일반적으로 프로세서에 있는 MMU(Memory Management Unit)의 지원이 필요한 가상 메모리 관리(Virtual Memory Management) 메커니즘을 채택합니다. 먼저 PA와 VA의 개념을 소개한다.

1.PA(물리적 주소)---물리적 주소

 프로세서에 MMU가 없거나, MMU가 있지만 활성화되지 않은 경우 CPU 실행 장치에서 보낸 메모리 주소가 프로세서로 직접 전송됩니다. 칩 핀을 사용하여 메모리 칩(이하 가상 메모리와 구별하기 위해 물리적 메모리라고 함) 수신에 의해 처리되는데, 이를 아래 그림과 같이 PA(Physical Address, 이하 PA라고 함)라고 합니다.

가상 메모리 관리에 대한 자세한 설명

Physical Address

2.VA (Virtual Address) ---Virtual Address

프로세서에 MMU가 활성화되어 있으면 CPU 실행 장치에서 보낸 메모리 주소를 MMU에서 가로챕니다. CPU에서 MMU로 가는 것을 Virtual Address(이하 VA)라고 하며, MMU는 이 주소를 다른 주소로 변환하여 CPU 칩의 외부 주소 핀으로 전송하는데, 즉 그림과 같이 VA를 PA로 매핑한다. 아래 그림.

가상 메모리 관리에 대한 자세한 설명

가상 주소

 32비트 프로세서라면 내부 주소 버스는 32비트이고 CPU 실행 장치에 연결되지만(그림에는 주소 라인 4개만 개략적으로 그려져 있음), MMU 변환 후 외부 주소 버스는 반드시 32일 필요는 없습니다. -조금. 즉, 가상 주소 공간과 물리적 주소 공간은 독립적입니다. 32비트 프로세서의 가상 주소 공간은 4GB인 반면, 물리적 주소 공간은 4GB보다 크거나 작을 수 있습니다.

 MMU는 페이지 단위로 VA를 PA에 매핑합니다. 32비트 프로세서의 페이지 크기는 일반적으로 4KB입니다. 예를 들어 MMU는 매핑 항목을 통해 VA의 0xb7001000~0xb7001fff 페이지를 PA의 0x2000~0x2fff 페이지로 매핑할 수 있습니다. 물리적 메모리의 페이지를 물리적 페이지 또는 페이지 프레임이라고 합니다. 가상 메모리의 어떤 페이지가 물리적 메모리의 어떤 페이지 프레임에 매핑되는지는 페이지 테이블(페이지 테이블)에 설명되어 있습니다. 페이지 테이블은 물리적 메모리에 저장되어 VA가 어떤 PA를 사용해야 하는지 결정합니다. 에 매핑됩니다.

3. 프로세스 주소 공간

프로세스 주소 공간
가상 메모리 관리에 대한 자세한 설명

 x86 플랫폼의 가상 주소 공간은 0x0000 0000~0xffff ffff입니다. 일반적으로 처음 3GB(0x0000 0000~0xbfff ffff)는 사용자 공간이고 마지막 1GB(0xc000 0000~0xffff ffff)는 커널 공간입니다.

  텍스트 세그먼트 및 데이터 세그먼트

  • 텍스트 세그먼트(.text 세그먼트, .rodata 세그먼트, .plt 세그먼트 등 포함) /bin/bash에서 메모리로 로드되며, 접근 권한은 r-x입니다.

  • 데이터 세그먼트(.data 세그먼트, .bss 세그먼트 등 포함) /bin/bash에서도 메모리로 로드되며 액세스 권한은 rw-입니다.

힙 및 스택

  • Heap: 힙은 단순히 컴퓨터 메모리에 남아 있는 공간입니다. 여기서 malloc 함수는 메모리를 동적으로 할당합니다. 동적으로 메모리를 할당하면 힙 공간이 더 높은 주소로 늘어날 수 있습니다. 힙 공간의 주소 상한선을 Break라고 합니다. 힙 공간을 높은 주소로 늘리려면 Break를 발생시켜 새로운 가상 메모리 페이지를 물리적 메모리에 매핑해야 합니다. 이는 malloc 시스템 호출을 통해 달성됩니다. 함수는 또한 brk를 호출하여 커널 메모리에서 할당을 요청합니다.

  • Stack: 스택은 특정 메모리 영역으로, 높은 주소 부분은 프로세스의 환경 변수 및 명령줄 매개변수를 저장하고, 낮은 주소 부분은 함수 스택 프레임을 저장하며, 스택 공간 그러나 실제로 힙 공간만큼 성장할 여지가 많지 않습니다. 왜냐하면 실제 애플리케이션이 동적으로 많은 양의 메모리를 할당하는 것은 드문 일이 아니지만 수십 개의 심층 함수 호출과 각 계층이 있기 때문입니다. 호출에는 지역 변수가 많이 있습니다.

프로그램 작성 시 메모리 할당에 주의하지 않으면 힙, 스택에서 다음과 같은 문제가 발생할 수 있습니다.

  1. 메모리 누수: 함수에 malloc을 전달하는 경우 힙에 공백을 만들고 스택에 포인터 변수를 선언하여 저장한 다음 함수가 종료되면 포인터 변수를 포함하여 함수의 멤버 변수가 해제되고 해당 공간은 복구되지 않습니다. 출시된. 시간이 지남에 따라 다음과 같은 메모리 누수 문제가 발생할 수 있습니다.

  2. 스택 오버플로: 스택에 너무 많은 데이터(예: 대형 구조 및 배열)를 넣으면 "스택 오버플로" 문제가 발생할 수 있으며 프로그램이 종료됩니다. 이 문제를 방지하려면 이러한 변수를 선언할 때 힙 공간을 적용하기 위해 malloc을 사용해야 합니다.

  3. 와일드 포인터세그먼트 오류: 포인터가 가리키는 공간이 해제된 경우 포인터를 사용하여 해제된 공간에 액세스하려고 하면 "세그먼트 오류" 질문이 발생합니다. 이 시점에서 포인터는 와일드 포인터가 되었으며 와일드 포인터는 시간에 맞춰 수동으로 지워야 합니다.

4. 가상 메모리 관리의 역할

  1. 가상 메모리 관리는 물리적 메모리에 대한 접근 권한을 제어할 수 있습니다. 물리적 메모리 자체는 액세스를 제한하지 않으며 모든 주소를 읽고 쓸 수 있지만 운영 체제에서는 CPU 모드 및 MMU의 메모리 보호 메커니즘을 사용하여 서로 다른 액세스 권한을 갖습니다.

  2. 가상 메모리 관리의 주요 기능은 각 프로세스가 독립적인 주소 공간을 갖도록 하는 것입니다. 소위 독립 주소 공간은 서로 다른 프로세스의 동일한 VA가 MMU에 의해 서로 다른 PA에 매핑되고 특정 프로세스의 모든 주소에 액세스할 수 없음을 의미합니다. 이로 인해 모든 프로세스가 잘못된 실행으로 인해 불법적인 메모리 액세스가 발생합니다. 명령이나 악성 코드는 실수로 다른 프로세스의 데이터를 다시 쓰지 않으며 다른 프로세스의 작동에 영향을 미치지 않으므로 전체 시스템의 안정성을 보장합니다. 반면에 각 프로세스는 자신이 전체 가상 주소 공간을 독점적으로 소유한다고 생각하므로 각 프로세스의 주소 범위가 충돌하는지 여부를 고려할 필요 없이 링커와 로더의 구현이 더 쉬울 것입니다.

프로세스 주소 공간은 독립적입니다가상 메모리 관리에 대한 자세한 설명是独立的

    VA에서 PA로의 매핑은 메모리 할당 및 해제에 편리함을 제공합니다. 불연속적인 물리적 주소를 가진 여러 메모리 블록을 연속적인 메모리 블록으로 매핑할 수 있습니다. 가상 주소. 예를 들어, malloc을 사용하여 큰 메모리 공간을 할당하려는 경우 여유 물리적 메모리는 충분하지만 연속 여유 메모리가 충분하지 않은 경우 여러 개의 불연속적인 물리적 페이지를 할당하고 이를 연속적인 가상에 매핑할 수 있습니다. 주소 범위.
불연속 PA를 연속 VA가상 메모리 관리에 대한 자세한 설명

에 매핑할 수 있습니다.

  1. 시스템이 동시에 많은 프로세스를 실행하는 경우 각 프로세스에 할당된 메모리의 합은 실제 사용 가능한 물리적 메모리보다 클 수 있습니다. 이 경우에도 가상 메모리 관리를 통해 각 프로세스가 정상적으로 실행될 수 있습니다. 각 프로세스에는 가상 메모리 페이지만 할당되기 때문에 이러한 페이지의 데이터를 물리 페이지에 매핑하거나 물리 페이지를 차지하지 않고 디스크에 임시 저장할 수 있습니다. 또는 스왑 장치라고 하는 디스크 파일일 수도 있습니다. 물리적 메모리가 충분하지 않으면 자주 사용되지 않는 일부 물리적 페이지의 데이터가 임시로 스왑 장치에 저장됩니다. 그런 다음 물리적 페이지는 사용 가능한 것으로 간주되어 프로세스에 재할당될 수 있습니다. ). 프로세스가 스왑 아웃된 페이지를 사용하려는 경우 이를 스왑 장치에서 물리적 메모리로 다시 로드합니다. 이를 스왑 인(페이지 인)이라고 합니다. 교체 작업과 교체 작업을 총칭하여 페이징이라고 합니다. 따라서:

    시스템에 할당할 수 있는 총 메모리 양=물리적 메모리 크기+크기 아래 그림과 같이 스왑 장치

을 선택합니다. 첫 번째 그림은 교체되어 물리적 페이지의 데이터를 디스크에 저장하고 주소 매핑을 해제하고 물리적 페이지를 해제하는 것입니다. 두 번째 그림은 교체되어 사용 가능한 물리적 페이지를 할당하고 디스크 임시 페이지를 메모리에 다시 로드하고 주소 매핑을 설정하는 것입니다.

가상 메모리 관리에 대한 자세한 설명

페이지 변경

5.malloc 및 free

C 표준 라이브러리 함수 malloc은 힙 공간에 메모리를 동적으로 할당할 수 있으며 해당 하위 계층은 brk 시스템 호출을 통해 운영 체제의 메모리에 적용됩니다. 동적으로 할당된 메모리를 모두 사용한 후에는 free로 해제하거나 더 정확하게는 malloc으로 반환하여 다음에 malloc이 호출될 때 메모리를 다시 할당할 수 있습니다.

1 #include <stdlib.h>2 void *malloc(size_t size);  //返回值:成功返回所分配内存空间的首地址,出错返回NULL3 void free(void *ptr);</stdlib.h>
로그인 후 복사

malloc的参数size表示要分配的字节数,如果分配失败(可能是由于系统内存耗尽)则返回NULL。由于malloc函数不知道用户拿到这块内存要存放什么类型的数据,所以返回通用指针void *,用户程序可以转换成其它类型的指针再访问这块内存。malloc函数保证它返回的指针所指向的地址满足系统的对齐要求,例如在32位平台上返回的指针一定对齐到4字节边界,以保证用户程序把它转换成任何类型的指针都能用。

动态分配的内存用完之后可以用free释放掉,传给free的参数正是先前malloc返回的内存块首地址。

示例

举例如下:

 1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <string.h> 4 typedef struct { 5     int number; 6     char *msg; 7 } unit_t; 8 int main(void) 9 {10     unit_t *p = malloc(sizeof(unit_t));11     if (p == NULL) {12         printf("out of memory\n");13         exit(1);14     }15     p->number = 3;16     p->msg = malloc(20);17     strcpy(p->msg, "Hello world!");18     printf("number: %d\nmsg: %s\n", p->number, p->msg);19     free(p->msg);20     free(p);21     p = NULL;22     return 0;23 }</string.h></stdlib.h></stdio.h>
로그인 후 복사

 

说明

  • unit_t *p = malloc(sizeof(unit_t));这一句,等号右边是void *类型,等号左边是unit_t *类型,编译器会做隐式类型转换,我们讲过void *类型和任何指针类型之间可以相互隐式转换。

  • 虽然内存耗尽是很不常见的错误,但写程序要规范,malloc之后应该判断是否成功。以后要学习的大部分系统函数都有成功的返回值和失败的返回值,每次调用系统函数都应该判断是否成功。

  • free(p);之后,p所指的内存空间是归还了,但是p的值并没有变,因为从free的函数接口来看根本就没法改变p的值,p现在指向的内存空间已经不属于用户,换句话说,p成了野指针,为避免出现野指针,我们应该在free(p);之后手动置p = NULL;

  • 应该先free(p->msg),再free(p)。如果先free(p),p成了野指针,就不能再通过p->msg访问内存了。

6.内存泄漏

  如果一个程序长年累月运行(例如网络服务器程序),并且在循环或递归中调用malloc分配内存,则必须有free与之配对,分配一次就要释放一次,否则每次循环都分配内存,分配完了又不释放,就会慢慢耗尽系统内存,这种错误称为内存泄漏(Memory Leak)。另外,malloc返回的指针一定要保存好,只有把它传给free才能释放这块内存,如果这个指针丢失了,就没有办法free这块内存了,也会造成内存泄漏。例如:

1 void foo(void)2 {3     char *p = malloc(10);4     ...5 }
로그인 후 복사

 foo 함수가 반환되면 로컬 변수 p의 메모리 공간을 해제해야 합니다. 이 함수가 가리키는 메모리 주소가 손실되고 이 10바이트는 해제될 수 없습니다. 메모리 누수 버그는 범위를 벗어난 액세스와 같은 프로그램 실행 오류를 일으키지 않기 때문에 찾기가 어렵습니다. 적은 양의 메모리 누수는 프로그램의 올바른 작동에 영향을 미치지 않습니다. 시스템 메모리로 인해 페이지가 자주 변경되어 현재 프로세스에 영향을 미칠 뿐만 아니라 전체 시스템 속도가 느려집니다.

 malloc과 free에는 특별한 경우가 있습니다. malloc(0)에 대한 호출도 적법하며 NULL이 아닌 포인터를 반환합니다. 이 포인터는 해제를 위해 free로 전달될 수도 있지만 이 포인터를 통해 메모리에 액세스할 수는 없습니다. free(NULL)도 적법하고 아무 작업도 수행하지 않지만 와일드 포인터를 해제하는 것은 불법입니다. 예를 들어 먼저 malloc을 호출하여 포인터 p를 반환한 다음 free(p)를 연속해서 두 번 호출하면 다음과 같이 됩니다. 런타임 오류를 생성합니다.

위 내용은 가상 메모리 관리에 대한 자세한 설명의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

관련 라벨:
원천:php.cn
본 웹사이트의 성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.
최신 이슈
인기 튜토리얼
더>
최신 다운로드
더>
웹 효과
웹사이트 소스 코드
웹사이트 자료
프론트엔드 템플릿