프로세스 메모리 구조

Groot·2022년 10월 17일
1

TIL

목록 보기
87/148
post-thumbnail

TIL

🌱 난 오늘 무엇을 공부했을까?

📌 프로세스 메모리 구조

  • 프로그램이 실행되기 위해서는 먼저 프로그램이 메모리에 로드(load)되어야 한다. 또한, 프로그램에서 사용되는 변수들을 저장할 메모리도 필요하다.

📍 운영체제가 제공하는 메모리 공간

  1. Text(code) 영역
  2. Data 영역 (BSS, GVAR)
  3. Stack 영역
  4. Heap 영역

🔗 그림 1



🔗 그림 2


📍 Stack 영역

  • 프로그램이 자동으로 사용하는 메모리 영역으로 함수 호출과 관계되는 지역변수와 매개변수가 저장된다.

  • 함수 호출 시 생성되며, 함수가 끝나면 반환된다.

  • stack 사이즈는 각 프로세스마다 할당되지만 프로세스가 메모리에 로드될 때 stack 사이즈가 고정되어 있어 런타임 시 stack 사이즈를 바꿀 수 없다.

  • 명령 실행 시 자동으로 증가 또는 감소하기 때문에 보통 메모리의 마지막 번지를 지정한다.(후입선출(LIFO, Last-In First-Out) 방식)

  • 스택 영역은 메모리의 높은 주소에서 낮은 주소의 방향으로 할당된다.

    커널 영역을 가장 최상위 메모리 주소에 할당하고 그 밑에 스택영역을 할당하는 방법으로 커널 영역에 대한 침범을 막는다.


📍 Heap 영역

  • 필요에 의해 메모리를 동적으로 할당할 때 사용하는 메모리 영역으로 동적 메모리 영역이라고 부른다.

  • 메모리의 힙(heap) 영역은 사용자가 직접 관리할 수 있는 '그리고 해야만 하는' 메모리 영역이다.(스위프트는 ARC를 통해 힙에 할당된 메모리가 더 이상 쓸모 없어지면(참조되지 않으면) 자동으로 해제)

  • 힙 영역은 메모리의 낮은 주소에서 높은 주소의 방향으로 할당된다.

  • 메모리 주소 값에 의해서만 참조되고 사용되는 영역이다.

    • 위의 stack과 heap영역은 사실 같은 공간을 공유한다. heap이 메모리의 낮은 주소부터 할당되면 stack은 높은 주소부터 할당되는 식이다.
    • 그래서 각 영역이 상대 공간을 침범하는 일이 발생할 수 있는데 이를 각각 stack overflow, heap overflow 라고 한다.

📍 Data 영역 (BSS, GVAR)

  • 프로그램이 실행될 때 생성되고 프로그램이 종료되면 시스템에 반환되며, 전역변수, 정적변수, 배열, 구조체 등이 저장된다.

  • Data 영역은 다시 BSS 영역과 Data(GVAR) 영역으로 나누어지는데, 초기화된 데이터는 Data 영역에 저장되고, 초기화되지 않은 데이터는 BSS 영역에 저장된다.

  • BSS영역, Data영역을 구분하는 이유?
    - 초기화 된 데이터는 초기 값을 저장해야 하므로 Data 영역에 저장되어 rom에 저장된다. 하지만 초기화 되지 않은 데이터 까지 rom에 저장되면 큰 size의 rom이 필요하므로 구분한다. ( 초기화 되지 않은 데이터는 ram에 저장)

    Stack과 Data를 구분하는 이유

    전역 변수(global variables)는 어떤 함수에서도 접근 할 수 있기 때문에 Data로 따로 관리를 해주는 것.
    스택 구조의 특성을 공부해보자.


📍 Text (Code) 영역

  • 텍스트 영역은 실행 명령을 포함하는 코드들이 들어가는 부분이다.

  • 프로그램을 시작 할 때 컴파일한 프로그램(기계어)이 저장되어 있고, 읽기 전용 영역이기에 프로세스가 함부로 변경 할 수 없고 변경 시 오류를 발생시킨다.

  • 코드 자체를 구성하는 메모리 영역으로 Hex 파일이나 Bin 파일 메모리이다. 프로그램 명령이 위치하는 곳으로 기계어로 제어되는 메모리 영역이다.


📍 스택 프레임(stack frame)

  • 함수가 호출되면 스택에는 함수의 매개변수, 호출이 끝난 뒤 돌아갈 반환 주소값, 함수에서 선언된 지역 변수 등이 저장된다.

  • 이렇게 스택 영역에 차례대로 저장되는 함수의 호출 정보를 스택 프레임(stack frame)이라고 한다.

  • 이러한 스택 프레임 덕분에 함수의 호출이 모두 끝난 뒤에, 해당 함수가 호출되기 이전 상태로 되돌아갈 수 있다.

  • iOS에서 스택 오버 플로우 발생 시 어플이 죽어 버릴 수 있음


📍 스택 프레임의 동작 방식

int main(void){ 
    func1();  // func1() 호출

    return 0;
}

void func1(){
    func2();  // func2() 호출
}

void func2(){}
  1. 프로그램이 실행되면, 가장 먼저 main() 함수가 호출되어 main() 함수의 스택 프레임이 스택에 저장.
  2. func1() 함수를 호출하면 해당 함수의 매개변수, 반환 주소값, 지역 변수 등의 스택 프레임이 스택에 저장.
  3. func2() 함수를 호출하면 해당 함수의 스택 프레임이 추가로 스택에 저장.
  4. func2() 함수의 모든 작업이 완료되어 반환되면, func2() 함수의 스택 프레임만이 스택에서 제거.
  5. func1() 함수의 호출이 종료되면, func1() 함수의 스택 프레임이 스택에서 제거.
  6. main() 함수의 모든 작업이 완료되면, main() 함수의 스택 프레임이 스택에서 제거되면서 프로그램이 종료.

📍 스택 오버플로우(stack overflow)

  • 만약 재귀 호출이 무한히 반복되면, 위 그림에서 Step 3 이후로는 재귀 호출에 의한 스택 프레임이 계속해서 쌓이게 된다.

  • 이렇게 스택의 모든 공간을 다 차지하고 난 후 더 이상의 여유 공간이 없을 때 또 다시 스택 프레임을 저장하게 되면, 해당 데이터는 스택 영역을 넘어가서 저장된다.

  • 스택영역을 넘어가는 문제가 스택 오버플로우

버퍼 오버플로(영어: buffer overflow) 또는 버퍼 오버런(buffer overrun)은 메모리를 다루는 데에 오류가 발생하여 잘못된 동작을 하는 프로그램 취약점이다.
컴퓨터 보안과 프로그래밍에서는 프로세스가 데이터를 버퍼에 저장할 때 프로그래머가 지정한 곳 바깥에 저장하는 것을 의미한다.
벗어난 데이터는 인접 메모리를 덮어 쓰게 되며 이때 다른 데이터가 포함되어 있을 수도 있는데, 손상을 받을 수 있는 데이터는 프로그램 변수와 프로그램 흐름 제어 데이터도 포함된다.

이로 인해 잘못된 프로그램 기동이 나타날 수 있으며, 메모리 접근 오류, 잘못된 결과, 프로그램 종료, 또는 시스템 보안 누설이 발생할 수 있다.

📍 결론

  • 기본적으로 Swift는 코드에서 안전하지 않은 동작이 발생하는 것을 방지한다.
  • Swift 메모리는 자동으로 관리된다.
  • Swift == God

📍 Reference

http://tcpschool.com/c/c_memory_structure
https://kyu9341.github.io/%EC%9A%B4%EC%98%81%EC%B2%B4%EC%A0%9C/2020/10/04/OS_Process_Structure/
https://jusung.gitbook.io/the-swift-language-guide/language-guide/24-memory-safety
https://itwiki.kr/w/%EB%B2%84%ED%8D%BC_%EC%98%A4%EB%B2%84%ED%94%8C%EB%A1%9C%EC%9A%B0

profile
I Am Groot

0개의 댓글