일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
- realclass
- 개발자
- 괜찮음
- 화상영어
- 영어공부
- 월간
- 읽기
- 사이드
- Problem Solving
- 매일
- 스탭퍼
- Daily Challenge
- 운동
- 미드시청
- 프로젝트
- Writing
- 만화도
- 쓰릴오브파이트
- English
- 파비최
- 30분
- 3줄정리
- 링피트
- 영어원서읽기
- FIT XR
- 잡생각
- 리얼 클래스
- 10분
- leetcode
- 뭐든
- Today
- Total
파비의 매일매일 공부기록
DP 정복 - 1.2 재귀 호출과 메모리 본문
이번 절은 거의 컴파일러 및 운영체제 관련 내용이라고 봐도 무방하다.
일단 C 프로그램의 생명주기(컴파일 & 링크 후 실행파일 생성)에 대해 설명하고 실행파일이 실행되면 이를 '프로세스'라고 이야기한다.
프로세스 주소 공간 : 프로세스가 차지한 메모리(RAM) 영역
- 코드 영역(혹은 텍스트 영역) : 컴파일된 기계어 코드가 저장됨. 읽기 전용. 프로그램이 실행되는 동안 변경 불가. 같은 프로그램이 여러 개 실행되더라도 메모리에는 한 벌만 저장 가능하도록 여러 프로세스가 공유 가능. 이 영역의 크기는 프로그램이 메모리에 올라갈 때 정해짐
- 데이터 영역 : 모든 전역/정적 변수(로드 타임 변수)가 할당되는 공간. 프로그램이 로딩될 때 이 영역에 메모리가 할당됨. 그래서 전역/정적 변수를 로드 타임 변수라고도 부름. 모든 로드 타임 변수는 프로그램이 로딩될 때 초기화됨. 초기값이 없는 경우 해당 자료형의 0에 해당하는 값으로 초기화. 내부적으로 초기화/비초 기화된 변수 영역으로 나눠짐. 메모리에 올라갈 때 이 영역의 크기가 정해짐.
- 스택 영역 : 모든 활성 함수의 활성 레코드(스택 프레임)가 저장됨. 활성 함수는 현재 호출 중인 함수를 의미. 함수가 호출되면 활성 레코드가 생성되어 스택 영역의 최상단에 들어감. 함수가 종료되면 스택에서 삭제됨. 스택의 크기는 지속적으로 변함. 지역 변수는 활성화된 함수의 활성 레코드 내 메모리에 저장됨.(* 정적 변수는 예외) 기본값으로 초기화되지 않음. 의미 없는 값으로 변수가 채워짐. 활성 레코드에는 함수의 실행에 필요한 다른 정보도 저장. 스택 포인터는 항상 스택의 최상단 가리킴. 함수 호출 한 번에 하나씩 활성 레코드가 생성되기에 재귀 함수의 경우 스택 영역에 여러 벌의 활성 레코드가 존재할 수 있음.
- 힙 영역 : 프로그램이 실행되는 시점에 요청된 메모리 공간이 힙 영역에 할당. 동적 메모리 혹은 런타임 메모리라고 부름. C 언어에서는 힙에 할당된 메모리 초기화 불가. C++은 가능. 메모리에 이름을 붙일 수 없으며 이 영역을 가리키는 포인터를 통해서만 접근 가능. 그러므로 이 메모리 주소를 잃어버리면 더 이상 접근할 수 없기에 메모리 누수가 생길 수 있음. C, C++로 프로그램 작성 시 발생하는 큰 오류의 원인 중 하나. 힙 영역과 스택 영역은 같은 공간을 공유하며 점점 가까워지는 방향으로 증가.
프로그램 로딩 과정 : 실행 코드를 메모리에 올리는 작업
- 코드를 코드 영역으로 보내기 : 이진 기계어 코드 형태. 명령 포인터는 현재 실행 중인 명령의 주소를 가리킴.
- 데이터 영역의 전역 변수 및 정적 변수의 메모리 할당 : 상기에 서술
- 전역 및 정적 변수 초기화 : 상기에 서술
함수가 호출되는 동안 내부에서 일어나는 일
1. 레지스터의 값, 명령 포인터의 값 등 호출하는 상태의 값은 메모리에 저장됨
2. 호출된 함수의 활성 레코드가 생성되어 스택의 제일 위에 저장됨. 호출된 함수의 지역 변수는 활성 레코드 내의 메모리에 할당됨.
3. 명령 포인터는 호출된 함수의 첫 번째 실행 가능한 명령으로 이동함.
4. 호출된 함수의 실행을 시작.
호출된 함수를 종료하고 돌아올 때의 절차
1. 함수의 반환 값을 레지스터 어딘가에 저장
2. 호출된 함수의 활설 레코드를 메모리에서 삭제. 스택의 크리 줄며 해제된 메모리는 다시 사용 가능한 상태로 바뀜.
3. 호출한 함수의 상태가 함수 호출 이전으로 복원됨. 함수를 호출할 때 메모리에 저장했던 레지스터 값, 명령 포인터의 값들을 원래의 위치로 복원
4. 명령 포인터는 호출한 함수의 함수 호출 전의 위치를 다시 가리킴, 거기서부터 호출한 함수의 실행 재개
5. 함수를 호출한 지점은 호출한 함수에서 반환된 값으로 치환.
C언어의 경우 함수의 비용이 크기 때문에 매크로를 이용하는 경우도 종종 있음.
Stack overflow를 일으킬 수 있는 코드도 소개함.
재귀 호출 사용/미사용에 대한 메모리 할당 차이를 소개. 당연히 재귀 호출을 사용할 경우 메모리를 많이 차지함. 재귀 호출이 될수록 스택에 쌓이기 때문.
정적 변수와 전역 변수는 함수의 반환 값으로 초기화할 수 없는 케이스 소개.
메모리 배치를 알면 문제 풀이에 도움이 된다고 저자는 말하는데..
글쎄..? 모르는 것보단 낫긴 하는데, 면접 질문에 대한 답이면 모를까. 이렇게 상세하게 알 필요가 있을까 싶다.
어쨌든 이번 절은 이걸로 마무리.
'Study > Algorithm 문제풀이' 카테고리의 다른 글
DP 정복 - 2.2 하위 문제의 반복 계산 (0) | 2021.08.23 |
---|---|
DP 정복 - 2.1 최적의 하위 구조 (0) | 2021.08.22 |
DP 정복 - 1.1 재귀 접근 방법이란? (0) | 2021.08.20 |
구체 수학 - #2.7 무한합 (0) | 2021.07.17 |
구체 수학 - #2.6 유한/무한 미적분 (0) | 2021.07.16 |