Process Architecture
초기 컴퓨터에는 하나의 프로그램만 메모리에 올려서 실행했었다.
그런데 여러 프로그램을 동시에 실행하려 하자(단일 프로그램에서도 발생한 문제긴하지만 일단 발생하는 문제는) 메모리 충돌이라는 문제가 생기게 되었다.
- 코드(명령)와 데이터가 뒤섞여 메모리를 덮어쓰는 문제
- 변수나 함수 주소가 충돌이 남
- 다른 프로그램 메모리를 침범해 시스템 오류 발생
이를 해결하기위해서 os에서는 각 프로세스에 독립적인 메모리 공간을 주게 되었고 그 공간을 효율적으로 관리하기 위해 코드 데이터 스택 힙으로 영역을 나누었다.
위에서 언급했듯 하나의 실행중인 프로세스는 보통 아래와 같은 주요 영역으로 구성된다.
- 코드영역: 실행해야할 기계어 명령을 저장한다. 읽기 전용이며 여러 프로세스간 공유가 가능하다
- 데이터 영역: 전역 변수 static 변수 등을 저장하고 프로그램 시작시 초기화되며 크기가 고정되어있다.
- 힙: 동적 메모리 new, malloc등을 저장하고 런타임시 크기가 변화하며 수동 해제가 필요하다.
- 스택: 함수 호출시 지역 변수, 매개변수를 저장한다 lifo 구조에 종료시 자동 해제다.
Code Area #
컴파일된 기계어 명령이 저장되어 있고 read only라서 실수로 코드를 덮어쓴느 버그가 방지된다. 예시로 함수 정의 코드등이 있다.
Data Area #
전역 변수 int a = 10; or static 변수등이 저장된다.
프로그램이 시작할때 한 번 로드되고 종료시까지 유지되는 데이터다.
다시 말해서 프로그램 전체에서 공유되는 메모리라고 보면 된다.
Heap Area #
malloc(), new 같은 동적 할당으로 생성된 객체가 존재하는 공간이다.
프로그래머가 직접 크기를 지정해 만들 수 있고, 반드시 free or delete로 해제해야한다.
그렇지 않으면 메모리 누수가 발생하기 때문
Stack Area #
함수 호출시 지역 변수, 매개변수, 리턴 주소가 저장된다.
함수가 끝나면 자동으로 해제되어 관리가 편하다.
하지만 크기가 한정되어 있어서 너무 깊은 재귀나 큰 배열 선언시 스택 오버플로우가 날 수 있으니 주의
결과적으로 이 구조를 통해 프로세스간 충돌 문제를 해결하게 된것이다.
코드와 데이터가 섞여 메모리를 침범하는 것은 코드 영역 데이터 영역을 분리함으로써 얻었고.
전역 변수와 함수 지역 변수의 생명주기 충돌은 data vs stack으로 구분했으며
런타임에 크기가 달라지는 데이터 관리 어려움은 heap 도입으로 동적 메모리를 지원했으며
여러 함수 호출시 변수 저장 위치 충돌은 stack 구조로 호출 순서를 관리했다.
결과적으로
- 메모리 보호
- 효율적인 메모리 사용
- 안정적 프로그램 실행 구조 확립
- 함수 호출 및 지역변수 관리 자동화
를 이루기 위해서 태어난 구조인것이다.
여기서 보면 처음에 문제 제기는 다른 프로세스간의 충돌을 막기 위해서 생겨났다고 본 줄 알았는데 이점을 보니 한 프로세스 내에서 나는 내부충돌도 함께 해소된거같지 않은가?
프로세스마다 독립적인 메모리 공간이 생겨도 하나의 프로세스 안에서 코드 데이터 스택 힙이 서로 얽히는 문제가 발생했었다.
예를 들어 함수 호출이 많아지면 스택이 커지고 힙 영역을 침범한다거나 전역 변수와 코드가 섞이면 코드 덮어쓰기가 된다거나
그래서 프로세스 내부에도 자기 자신 안의 역할별 메모리 구역을 구분하자 이 원칙이 적용되어 코드 데이터 힙 스택 구조가 만들어 진 것이다.
프로세스 하나일때도 충분히 발생할 수 있었지만 잘 발생하지 않다가. 여러 프로세스를 띄우면서 근본적으로 하나일때도 발생할수있던 문제를 찾은거고
구조를 분리해 1차적인 프로세스 하나만 있을때 문제를 깬 이후에
가상 메모리, mmu, 프로세스 격리같은 운영체제의 수준의 기술로 해결되었다.
결과적으로 프로세스가 여러개 충돌 문제는 운영체제가 다른 방법으로 해결한거였던걸로