728x90

Segment

  • 메모리 보호를 수행하는 일반적인 방법 가운데 하나

💡 페이징 : 프로세스를 물리적인 단위로 분할하여 메모리에 적재

 

  • 세그먼트 방식은 논리주소를 물리주소로 매핑하는 방식으로 구현한다.
    • 세그먼트는 논리적인 단위로 메모리를 로드하기 때문에 메모리 보호가 쉽다.
    • 각 세그먼트들의 크기는 균일하지 않다.

 

  • 컴파일러에 의해 자동적으로 프로그램이 로드될 때 세그먼트가 나뉘게 된다.
  • 간단히 말해서 메모리에 적재될 때 나뉘는 영역!

 

 

 


Memory Structure

 

주소 영역 내용 메모리 할당 시기
0x0000
(Low Address)
code(text) * 코드, 함수, 제어문 등 실행할 프로그램의 코드가 저장되는 영역 * Compile Time Memory 할당
* 크기 고정
  data data * 초기값이 있는 전역변수, static 변수, 정적 배열, 정적 구조체 등 저장
  bss(Block Started by Symbol) * 전역으로 선언된 초기화 되지 않은 데이터 영역  
  heap * 동적 할당 객체에 대한 영역
* High Address 방향으로 추가 할당
* Run Time Memory 할당
* 가변적 크기
  자유영역 * Heap Overflow : heap 영역이 증가하여 stack 영역을 침범
* Stack Overflow : stack 영역이 증가하여 heap 영역을 침범
 
0xFFFF
(High Address)
stack * 지역변수, 매개변수, 리턴 값 등 임시로 사용하는 것들에 대한 영역
* 매개 변수와 리턴값은 함수 호출 시 생성, 함수 수행 종료시 반환
* Low Address 방향으로 추가 할당
 

 

 

 


Text(Code) Segment

  • 코드들이 바이너리화 되어 저장된다.
    • 코드만 저장하고 있기 때문에 쓰기가 금지되어있다.
    • 텍스트 세그먼트에 쓰려는 시도가 있을 경우, 운영체제가 그 사실을 사용자에게 알리고 프로그램은 종료된다.
    • 텍스트 세그먼트가 읽기 전용일 때, 장점으로는 한 종료의 프로그램을 여러 번, 여러 개 실행해도 텍스트 세그먼트를 공유할 수 있다.
  • 프로세서가 여기서 명령어를 하나씩 가져와서 실행
  • 프로그램이 실행되면 EIP 레지스터의 위치가 텍스트 세그먼트의 맨 처음 위치로 설정된다.
    • EIP 레지스터 : 다음에 실행할 명령의 메모리 주소

 

 

 


Data Segment

  • 전역변수(global)과 정적변수(static)가 저장되는 메모리 공간
  • 해당 공간에 있는 데이터들은 초기값이 있는 전역변수, 배열, static으로 선언된 변수가 들어간다.
  • 이 공간은 이후 일정 메모리 접근 공간으로 사용이 가능하다.
    • → 프로그램 런타임에 자유롭게 수정 및 변경이 가능하다.

 

 

 


BSS(Block Stated Symbol) Segment

  • 전역 / 정적 변수 중 초기화 되지 않은 변수들이 저장되는 공간
    • C에서는 초기화되지 않은 정적 변수는 0이나 NULL 로 초기화된다.
    • 0과 NULL 모두 컴파일러에서는 모든 비트가 0인 비트패턴으로 표현한다.
    • → 해당 작업을 BSS 세그먼트에서 담당한다.

 

  • 컴파일 타임에는 BSS 세그먼트에 할당된 메모리는 메모리만 잡아놓고 초기화시키지 않는다.
    → 어느정도의 공간을 할당할 것이라는 정보만을 저장한다.

 

  • 런타임에 링크되어 올라가고 프로그램을 로드할 때 값이 0으로 초기화된다.
    +) 해당 메모리가 필요한 순간까지 OS가 0으로 초기화하는 작업을 지연하는 등 BSS 세그먼트를 효율적으로 구현한다.
  • BSS 영역은 어느 정도의 메모리를 확보할 것인지에 대한 정보만 미리 할당해놓고 있다가 런타임 이후에 메모리 영역이 확보된다.
    → 메모리 사용면에서 BSS가 더 효율적이다.
     💡 즉, 전역 / 정적 변수 선언시 초기화를 하지 않는 게 더 좋다!

 

 

 


Stack

1. 메모리를 블록처럼 쌓아놓는다.

2. 스택 영역에는 지역변수들과 매개변수 및 리턴주소가 저장된다.

  • 매개변수는 레지스터에 저장될 수도 있다.

3. 함수가 선언되면 할당되고, 함수 호출이 종료되면 해제 된다.

  • %rsp를 이용한다.
  • RSP(Extended Stack Pointer - 스택의 top위치를 가리키는 레지스터
  • 할당과 해제를 계속 반복하여, 사이즈가 계속 변한다.

4. stack(지역변수)을 프로그램 하면서 얼마나 사용할 지 미리 계산할 수 없다.

  • 메모리의 높은 주소에서 낮은 주소로 할당

5. 4byte 단위로 쪼갠다.
    4byte가 안되면 → 2byte → 1byte (32bit 기준)

 

 

 


Heap

  • Stack 🆚 Heap
    • Stack : 컴파일 타임에 크기 결정
    • Heap : 런타임에 동적으로 크기 결정

 

1. 메모리가 힙 영역에 아무렇게나 할당되어있다.

2. 힙에 저장된 데이터는 함수 호출이 종료되어도 해제되지 않는다.

  1. 개발자가 명시적으로 해제
  2. 프로그램 종료

3. 메모리 주소에 따라서 힙 데이터에 접근한다.

4. 힙 공간은 크기의 제약이 없다.

  1. 메모리가 충분하다면 힙 영역은 필요한만큼 확장될 수 있다.

5. 힙에서 발생되는 메모리 문제

  1. 사용이 종료된 데이터가 해제되지 않으면 프로그램이 종료될 때까지 메모리 공간을 차지한다.
  2. 프로그램은 힙에 데이터가 해제되었어도 메모리 주소에 따라서 접근할 수 있다.
  3. 힙 영역은 크기의 제한은 없지만 가용 메모리가 가득 찰 경우 커널의 OOM Killer에 의해 프로그램이 종료될 수 있다.

6. 메모리의 낮은 주소에서 높은 주소로 할당

7. 사실상 스택과 같은 영역을 공유한다.

  1. heap과 stack영역의 총합은 정해져있다.

8. 만약 스택과 힙이 겹칠경우, 마지막에 할당한 것에서 이름을 따서 stack overflow, heap overflow가 발생한다.

 

 

 


Memory management functions

  • 객체의 타입이 어떤 것 이던지 메모리를 할당할 수 있으며, 할당된 메모리에 대한 포인터 값을 리턴한다.
  • 할당이 성공할 경우, 반환되는 포인터는 개체에 대한 접근 또는 어떠한 객체로 이루어진 배열에 대한 접근을 위해 사용한다.
    • 공간이 명시적으로 할당 해제될 때까지
  • 할당된 개체의 수명은 할당시부터 할당 해제시까지 유지된다.
  • 각각의 메모리 영역 할당은 다른 객체의 영역과 분리된다.
  • 공간을 할당할 수 없으면 null 포인터가 반환된다.
  • 만약 요청되어지는 공간의 크기가 0인 경우에 해당 동작은 구현으로 정의된다.
    • null 포인터가 반환되어지거나 크기가 0이 아닌 것 처럼 동작한다.
    • But, 반환된 포인터로 개체에 접근하는데 사용되면 안된다.

 

  • 속도 : Stack > Data > Code > Heap

 

 

 


⭐ Summary

- 프로그램을 실행하게 되면 CPU 프로세서는 보조기억장치(HDD, SDD)에 있는 프로그램 정보를 읽어와,  RAM메모리(캐시, 주기억장치)에 로드한다. 

- 메모리 공간은 프로세스에 할당되어 CPU에 의해 수행된다.

- 이때, 프로그램이 저장되는 메모리 공간은 일반적으로 Code, Data, Stack, Heap의 4가지 세그먼트로 분류된다.

 

 

 


🔗 Reference

 

 

 

728x90

'🌱 Dev Diary > 📄 TIL' 카테고리의 다른 글

Team Session - File Descriptor(FD)  (1) 2022.12.11
Malloc Lab 구현  (0) 2022.12.08
RB Tree 구현  (0) 2022.12.06
RB Tree 이론  (1) 2022.11.29
C 정복하기(2) - 메모리 할당  (0) 2022.11.28