본문 바로가기

23년 1학기 학교공부/운영체제및실습

[OS] 메모리 주소의 종류와 Virtual Address Space

목차

    728x90
    반응형
    SMALL

    메모리 주소의 종류에는 다섯가지가 있다.

    1. Physical address(absolute address)
    메모리 유닛 하드웨어가 이용하는 주소이다.

    1GB짜리 메모리 반도체를 끼면 0번부터 1GB-1번지까지 바이트 단위로 번호가 매겨지는데, 이 번호가 physical address이다.
    메모리 유닛은 physical address를 보고 메모리 반도체 칩에서 바이트 위치를 찾아간다.

    2. Logical address
    프로그램 인스트럭션 내에 등장해서, 논리적인 연산에 이용되는 주소이다.
    따라서 인스트럭션을 실행하는 cpu(프로세서)가 바라보고 이용하는 주소이다.

    실제 메모리에 있는 주소와는 다르다.
    프로그램의 인스트럭션이 logical address를 포함하고 있지만, cpu가 해당 인스트럭션을 실행하려면 그 logical address에 해당되는 physical address를 알아내야 실제 메모리에 가서 값을 읽어올 수 있다.
    이와같이 인스트럭션 내부의 logical address를 physical address로 바꾸는 과정을 address translation(주소 변환)이라고 한다.

    3. Virtual address
    virtual memory에서 사용하는 logical address, 즉 가상의 주소를 말한다.
    virtual memory는 보조기억장치를 메인메모리처럼 이용하는 메모리 관리 기술이다.

    4. Relative address
    하나의 정해진 위치를 기준으로 얼마만큼 떨어져있는지를 표현하는 주소이다.
    logical address는 프로세스 시작 지점을 기준으로 얼마만큼 떨어져있는지를 표현하므로, relative address이다.

    예를 들어 메인메모리의 90000번지부터 90100번지 사이에 프로세스 a가 있다고 하자.
    이 90000번대 주소는 메모리 반도체의 주소이기 때문에 physical address이다.
    그리고 프로세스 a 내부에서 시작지점을 0번지로 지정하여 상대적으로 주소를 매길 수 있다.
    예를 들어 프로세스 a의 코드중에서 70번지로 점프하라고 하면 실제로 physical address는 90070번지가 되는 것이다.
    이때의 70번지가 logical address이다.
    이 프로세스가 virtual memory에 있다면 70번지는 logical address면서 virtual address가 된다.

    컴파일 시점의 바인딩와 load 시점의 바인딩 때 logical address와 physical address가 같다.
    하지만 실행 시점 바인딩때는 다르다.

     

    이 C프로그램을 보자.
    메인 function이 있고, argument를 전달받고, 내부에서 i라는 지역변수와 local_var라는 지역변수 두개를 선언한다.
    메인function 바깥에서는 a, b, glob라는 전역변수를 선언한다.

     

    이 프로그램을 예를 들어 gcc 컴파일러를 이용하여 컴파일하면 a.out이라는 실행파일이 만들어진다.
    이 a.out은 프로세스가 아니라 디스크에 저장된 하나의 파일에 불과하다.
    이 실행파일은 해당 파일에 대한 메타 데이터 정보를 가진 헤더와, 코드, 데이터, 데이터 영역의 일부인 bss, stack으로 구성된다.

    code 영역에 위 c프로그램의 코드가 들어가고,
    data 영역에 전역변수가 들어가고,
    bss 영역에 초기화되지 않은 전역변수가 들어가고,
    stack 영역에 지역변수가 저장도니다.

    이 실행파일을 더블클릭해서 실행시키면 보조기억장치에 virtual memory가 만들어지는데, 위 실행파일을 구성했던 code, data, bss, stack과 앞으로 써도되는 빈공간으로 구성된 4GB(32bit 컴퓨터의경우) 크기의 공간이다.
    32bit 컴퓨터라고 하는건 주소를 나타내는데 32bit, 즉 4byte를 쓸 수 있다는것이다.
    이 범위로 표현할 수 있는 주소는 최소 0에서 최대 2의 32제곱 -1bit, 즉 4GB-1이다.

    이런 virtual address space는 프로세스마다 하나씩 만들어진다. 이렇게 생성된 virtual address space에서 코드, 데이터, 스택이 메인메모리로 들어가면 cpu가 읽어서 실행하는 것이다.

     

    위 예시에서 프로세스 1번은 80000번지부터 100000번지까지 들어있고, 2번은 100001번지부터 150000번지까지, 3번은 150001번지부터 190000번지까지 들어있다.
    이렇게 메모리를 잡아주고 프로세스가 각각 들어가게 하는것이 메모리 관리의 메모리할당이다.
    위 그림은 가변 동적 할당 방법이라고 보이지만, 실제로는 페이징이라는 방법을 이용하여 할당한 것이다.

    또 위 그림에서 중요한 점은, 메인메모리와 virtual space 둘 모두 os가 들어있다는 점이다.
    이것은 메인 메모리의 os를 복사해서 디스크에 3개의 복사본이 존재한다는 뜻이 아니라, virtual space의 커널은 단지 3GB부터 4GB-1번지까지 메인 메모리에 있는 커널이 들어간다는 정보로만 존재할 뿐이고 실제로 디스크 공간을 차지하지 않는다.
    stack과 data사이의 빈 공간도 마찬가지로, 빈 공간의 크기 정보만 운영체제가 가지고 있고,
    또한 code도 정확히 말하면 실행파일의 코드와 같이 쓰기 때문에 인스트럭션을 메모리에 넣을 때 virtual memory에서 가져오는것이 아니라 한번더 가서 실행파일에서 가져온다.
    실제로 디스크에서 공간을 차지하고 있는 부분은 stack, data부분뿐이다.

    이때 stack와 data는 공유하지 않는 이유는 코드는 한번 컴파일하면 바뀌지 않지만, stack과 data는 프로그램이 실행되면서 계속 바뀌기 때문에 실행파일에 있는걸 쓰면 안되고 별도 공간을 잡아줘야한다.

    운영체제는 virtual address space의 각 영역의 시작주소와 끝주소를 PCB에 저장한다. 이렇게 저장하면 마치 디스크에 실제로 존재하는것처럼 보인다.

     

    위 그림은 한 프로세스의 virtual address space인데, 이는 page라고 불리는 작은 점선으로 나뉘어있다. 

    위 virtual address space에는 커널도 있으므로, 커널도 어떤 프로세스 몸체의 일부이다.


    stack은 커널 공간 바로 밑에 거꾸로 배치되어있다.

     

    리눅스 운영체제의 virtual address space를 좀더 자세히 보자.
    start_code와 end_code가 code 영역의 시작, 끝 주소를 의미하는 변수이다. 이런 변수들을 FCB에 저장하는것이다.
    그리고 shared memory나 라이브러리를 포함해서 사용할땐 data와 stack 영역 사이 빈공간에 잡는다.

    728x90
    반응형
    LIST