Linux_system

Linux Memory 관리

MasterOfAI 2022. 8. 19. 20:38

>free

 

free명령어 사용으로, 시스템의 총 메모리의 양과 , 사용 중인 메모리의 양을 알 수 있다. 

모든 단위는 KB 임

 

total : 시스템에 탑재된 전체 메모리 용량임. 위 예시에서는 16GB 임 

free :  표기상 이용하지 않는 메모리 

buff/cache : 버퍼 캐시 또는 페이지 캐시가 이용하는 메모리. 시스템의 빈 메모리 (free) 가 부족하면 커널이 해제함 

available  : 실질적으로 사용 가능한 메모리. free 필드값의 메모리가 부족하면 해제되는 커널 내의 메모리 영역 사이즈를 더한 값이다. 해제될 수 있는 메모리에는 버퍼 캐시나 페이지 캐시의 대부분 혹은 다른 커널 내의 메모리 일부가 포함된다. 

 

>sar -r 1

1초 단위로 메모리에 관련된 통계 정보를 얻을 수 있다. 

free 와 sar -r 에 의해 출력되는 결과 정보를 비교해 보면 아래와 같다. 

free total free buff/cache available
sar -r X kbmemfree kbbuffers + kbcached X

 

 

가상 메모리 

 

시스템에 탑재된 메모리를 프로세스가 직접 접근하지 않고, 가상 주소라는 주소를 사용하여 간접적으로 접근하도록 하는 방식을 말함.  프로세스에 보이는 메모리 주소를 '가상 주소', 시스템에 탑재된 메모리의 실제 주소를 '물리 주소' 라고 부른다. 각 프로세스 마다 접근 가능한 범위를 '가상 주소 공간' 이라고 부른다.  

프로세스는 물리 주소에 직접 접근 할 수 없으며, 모든 경우, 가상 주로를 통해 접근한다. 

커널은 내부적으로 '페이지 테이블' 이라는 표를 가지고 있어, 가상주소 <-> 물리주소 변환을 진행해 준다. 

가상 메모리는 전체 메모리를 페이지라는 단위로 나눠서 관리하고 있어서, 전환은 page 단위로 이루어 진다. 

페이지 테이블에서 한 페이지에 대한 데이터를 '페이지 테이블 엔트리'라고 부르며, 이 페이지 테이블 엔트리에는 가상 주소와 물리 주소의 대응 정보가 들어 있다. 페이지의 사이즈는 CPU의 아키텍처에 따라 다르다. 흔히 사용하는 x86_64 아키텍처의 페이지 사이즈는 4KB 이다. 

아래 그림은 , 물리 주소의 500 ~ 800 번지를 사용하는 프로세스 의 가상 주소 를 묘사한 것이며, 편의상 페이지 사이즈를 100바이트로 가정 한 것이다. 

 

만일 해당 프로세스에서 300번지 이후에 가상 주소에 접근하려 한다면 어떻게 되는가? 'page fault' 라는 interrupt 가 발생하여 kernel로 전달된다.  왜냐하면 해당 페이지 테이블 에서는 가상 주소 300번지 이상의 범위에 해당하는 물리 주소가 없기 때문이다. Kernel 이 page fault interrupt 를 받으면, SIGSEGV 시그널을 통해 해당 프로세스에 통지하고, 이 통지를 받은 프로세스는 강제 종료 된다. 

 

다음과 같이 code 를 짜고 실행하면, Seegmentation fault" 가 발생한다. 해당 프로세스가 SIGSEGV 시그널을 받았기 때문이다. 

 

 

프로세스가 생성될때 메모리가 할당되는 방법은 다음과 같다. 

 

1. 실행 파일을 읽어서 여러가지 보조 정보를 읽어 낸다. 다음과 같은 정보들을 일게 될 것이다. 

 

    코드 영역의 파일상 offset : 100

    코드 영역의 size : 100

    코드 영역의 메모리 맵 시작 주소 : 0

    데이터 영역의 파일상 offset : 200

    데이터 영역의 사이즈 : 200

    데이터 영역의 메모리 맵 시작 주소 : 100

    엔트리 포인트  : 0

 

2. 필요한 메모리 사이즈를 계산하고, 이 영역을 물리 메모리에 할당한 후, 필요한 데이터를 복사한다. 

3. 프로세스를 위한 페이지 테이블을 만들고 가상 주소 공간을 물리 주소 공간에 매핑 한다. 

4. 엔트리 포인트 주소에서 실행을 시작한다. (가상주소의 경우 0 번지 이고, 이것은 실제 물리 주소 500 번지)

 

5. 만일 프로세스가 새 메모리를 요구하면, 커널은 새로운 메모리를 할당하여 대앙하는 페이지 테이블을 작성한 후 할당된 메모리 (물리 주소)에 대응하는 가상 주소를 프로세스에 반환한다. 

 

 

다음과 같이 code 를 짜고, 실행하면 

결과는 아래와 같다. 

 

우선 address x7f5566d7e000 에대한 메모리 맵이 성공했다는 메시지가 나온다. 

그리고 그 전에는 존재 하지 않았던, "7f5566d7e000-7f556d17e000 rw-p 00000000 00:00 0"이라는 메모리 영역을 나타내는 행이 추가 되었다. 이 부분이 새로 확보된 메모리 영역이다. 

x7f5566d7e000 이 이 신규 영역의 시작주소 이고 

x7f556d17e000 이 마지막 주소 이다. 

 

마지막 주소 - 시작 주소로, 할당된 size를 계산 해 보면 정확히 104857600 byte = 100 MB 이다. 

 

 

실제로 C에서는 malloc() 으로 메모리를 할당하며 이때 byte 단위로 할당 된다. 하지만 glibc 는 내부적으로 mmap() system call을 사용하여 page 단위로 memory 를 할당 받는다. 이처럼 요청 받는 단위와 실제 할당 받는 단위이 비대칭을 극복하고자 glibc 는 사전에 mmap() 를 통해 커다란 메모리 영역을 확보하여 메모리 풀을 만들고, malloc()이 호출 되면 메모리 풀로 부터 필요한 양을 바이트 단위로 잘라내어 반환하는 처리를 한다. 풀로 만들어 둔 메모리에 더이상 빈 공간이 없으면 다시 한번 mmap()을 호출하여 새로운 메모리 영역을 확보한다. 

 

가상 메모리를 사용하면, 다음 문제들이 해결 됩니다. 

 

1. 단편화 문제 - 실제로는 메모리가 물리 주소지 여기 저기에 흩어져 있지만, 가상 주소에서는 연결되어 있기 때문에 이 문제가 해결됨 

2. 다른 용도의 메모리에 접근 가능한 문제 

3. 여러 프로세스를 다루기 곤란한 문제 - 가상 메모리는 프로세스별로 독립적으로 만들어 지기 때문에, 다른 프로세스의 메모리에 접근하는 오류가 발생할 가능성이 없다. 

 

 

 

 

 

 

출처 : 실습과 그림으로 배우는 리눅스 구조 , 다케우치 사토루저