메모리 관리에 대해 알아보자
컴퓨터 시스템의 필수 구성 요소는 cpu와 메모리 장치이다. 메모리를 할당 받아서 프로세스를 저장해야 프로그램을 수행할 수 있다.
이 장에서는 컴퓨터 시스템에 존재하는 하나의 메모리를 어떻게 나누어주는지 배워볼 수 있다.
페이징, 세그멘테이션을 사용해서 실제 메모리를 나누고 있다.
페이지 라는 것은 고정된 사이즈의 메모리 블록이다. 이것은 세컨더리 메모리에서 한번 읽어낼 때 사용되는 데이터의 사이즈와 같은 크기가 된다.
세그멘테이션이라는 것은 필요한 만큼의 블록을 할당하는 방법이다
먼저 메모리 관리의 요구사항
단순하게 메모리를 나누어 할당하여 프로세스를 넣어 주면 되지만 자세히 생각해보면 이러한 문제들을 해결해줘야 한다.
우리가 프로그램에서 재배치하는 과정이 필요한 이유
100번지로 가라고 지시한다
a라는 배열에 접근하는데 500번지부터 시작한다라고하는 코드가 있을 수 있다.
주소값을 바꿔줄 필요가 있다. 즉 0번지 시작 100번지→ 500번지 이동이 되면 1000번지 시작 →1100번지 1500번지 이렇게 재배치가 된다.
프로세스는 메모리에 접근하기 위해 permission을 관리해야한다.
보안이 뚫리는 일을 방지하기 위해 모든 메모리 참조는 실행시간에 확인이 되어야 한다.
소프트웨어만으로 이루어지지 않고 하드웨어로 보호를 한다.
각 프로세스는 예를 들어 인터넷 웹 서버 같은 경우 프로그램의 많은 부분은 공유될 수 있다. 동일한 복사본의 프로그램을 가지고 사용자의 접속을 받게 되는데 메모리 요구를 많이 줄일 수 있다.
메모리를 공유했을 때 protection에 문제가 생기지 안도록 공유할 수 있도록 메커니즘을 제공한다.
소프트웨어와 하드웨어를 사용해서해결한다.
프로그램은 여러가지 모듈로 구성된다.
프로그램은 코드 텍스트 데이타 heap(bss) 스택 세그먼트로 이루어진다. 세그먼트라는 것을 사용해서 할당하는데 이러한 세그먼트 구조를 ,논리적인 구조를 관리할 수 있어야 한다.
이러한 메모리는 물리적인 기억장소와 주소값을 갖기 때문에 관리해주어야 한다.
메모리라는 커다란 덩어리를 관리하면서 프로세스에게 나누어주어야 한다.
사용자가 관리하는게 아니라 os에서 전체 메모리 크기와 나누어 주어야하는지에 대한 정보를 관리하고 있다나 그것을 나누어준다.
그것이 얼마나 여유가 있는지 os가 관리 한다.
이러한 요구사항을 가지고 사람들이 real memory를 나눠주는 방법으로 첫 번째로 생각한 것이 Memory Partitioning이다.
프로세스를 만들기 위해서 메인 메모리를 여러 프로세스에게 잘라서 나누어 주어야 하는데
메모리를 파티션으로 나누어 주는 것이다.
파티션 나누는 기술
단점
고정된 사이즈다 보니 아주 크게 나누어야 할지 아주 작게 나누어야 할지 에 대한 문제가 있다
메인 메모리의 효율성이 비효율적이다.
실제로 100이 필요한데 1000을 할당하면 900이 남는데 이를 internal fragmentation이라고 한다.
같은 사이즈가 아니고 다른 사이즈로 할당하는 방법으로 발전했다.
작은 작업이 전체 공간을 낭비하는 문제가 생긴다.
고정 분할의 단점을 해결한 것
이 방법이 OS/MVT 라는 컴퓨터에서 사용됨
이름 그대로 동적으로 실행 시간에 필요한 만큼 할당한다.
이러한 데이터 조각들이 발생한다. 이러한 짜투리 메모리 공간을 External Fragmentation이라고 한다.
이 External Fragmentation이 많아지면 우리가 쓸 수 없는 메모리가 많아지기 때문에 shift를 해서 메모리를 유용하게 하는데 이를 compaction이라고 한다.
어느 메모리에 나누어 주는 방법(배치 전략)
Best-fit
First-fit
Next-fit
앞에 있는 시스템보다 통계적으로 더 잘 동작하는, fragmentation이 더 적게 남는 시스템이 buddy system이다.
고정된 사이즈와 동적 사이즈 파티셔닝을 섞은 것이다.
메모리 블록을 2^k에 해당하는 크기로 잘라서 사용하는 것이다.
이진 트리를 이용해서 관리 할 수 있다.
리눅스에서 버추얼 메모리라는 장치를 구동시키기 전에 커널이 메모리 할당하기 위해서 사용하는 리얼 메모리 관리 방법이다
리얼 메모리를 여러 방법으로 나누었을 때 Logical address를 Physical address로 바꾸어 주어야 한다.
프로그래밍 할 때 이 프로그램이 피지컬 메모리에 어디에 들어갈지 상관없이 만든다.
org 0 를 시작해서 만드는데 0번지가 아니라 100번지에 들어간다고 하면 피지컬 어드레스에 사상을 시켜줘야 하는 문제가 있다. 이를 해결하는 방법은 상대적으로 주소를 표현하는 방법이 있는데 이를 Relative addressing이라고 한다.
프로그램을 하드웨어에서 relocation하기 위해서는
사용자가 편리하게 쓸 수 있는 방법
고정된 사이즈의 크기로 메모리를 나누는데 아주 작게 나누어서 메모리를 할당
하드웨어를 가지고 5가지 문제를 해결할 수 있다.
메모리가 흩어져서 들어가는 경우 페이지 테이블이라는 것을 사용해서 해결
각 프로세스 마다 운영체제 의해 유지되는 페이지 테이블
물리적인 페이지(프레임)의 위치를 각 프로세스에 대해서 저장한다.
(각 프로세스의 페이지 테이블은 물리적인 페이지 프레임의 위치를 저장한다. )
물리적 주소를 생성하기 위해서(재배치를 위해서) 사용한다.
논리 주소 →물리 주소로 사상
1번지 페이지 번호가 주어지면 페이지 테이블을 이용해서 변환 나머지 offset은 그대로 가져다 쓰기
번역은 하드웨어에서 관리 페이지 테이블은 os에서 관리
프로그램은 세그먼트 단위로 나눌 수 있다. 여러 사이즈의 블록이 된다.
세그먼트 넘버와 offset으로 관리가 된다.
다이나믹 파티셔닝과 비슷하게 사용된다. internal fragmentation을 없앨 수 있따.
페이지 대신에 segmentation 넘버가 인덱스로 사용된다.
os가 하는 일은 process segment table을 유지 하는 일을 한다.
컴퓨터를 사용할 때 , 공인인증서나 인증정보에 있어서 사용할 시 많은 법적인 일을 할 수 있다. 그것이 해커에게 노출이 되면 그 정보를 사용해서 큰일이 일어날 수 있다.
한 세그먼트 내에서 다른 값들을 접근 할 수 있다. 서버에서 돌아가는 공용 프로그램 통신 프로그램에서 한 사용자가 다른 사용자의 세그먼트를 가로챌수 있다.
next_tag(str1); → str1 =”start”;
strncmp는 str1과 str2 8비트를 서로 비교
한 변수가 다른 변수의 영역을 침범하는 것, 하나의 프로그램의 데이터가 다른 영역의 프로그램을 덮어 쓰는 경우가 버퍼 오버플로우 공격이라고 한다.
메모리를 잘 보호하지 못하면 엉뚱한 일이 발생할 수 있다.
버퍼오버플로우 막기 위한 방법