2019. 4. 13. 02:14ㆍlayer7
오늘은 메모리 구조와 동적 할당에 대해 알아보겠습니다.
프로그램이 실행될 때는 운영체제의 의해서 메모리 영역이 4가지로 나뉘어 할당됩니다.
할당되는 메모리 구조는 위 그림과 같습니다.
코드 영역(Code area):
- 실행되는 프로그램의 코드가 저장되는 메모리 공간입니다.
다른 이름으로는 텍스트 영역(Text area)이라고 하며 말 그대로 c언어를 통해 작성한
코드들이 저장되는 영역입니다.
- CPU는 코드 영역에 저장된 명령어를 하나씩 가져가서 처리하게 됩니다.
데이터 영역(Data area)
- 메모리의 데이터(Data) 영역은 프로그램의 전역 변수와 정적(static) 변수가 저장
되는 영역입니다.
-전역변수와 정적 변수는 프로그램이 종료할 때까지 사라지지 않고 메모리 공간에 남아 있다는
점이 특징입니다.
데이터 영역에는 data segment 영역과 BSS(block stated by symbol)이 있다.
data segment 영역은 초기화 된 변수
bss 영역은
초기화 되지 않거나 0으로 초기화 된 전역 변수와 정적(static)
변수가 저장됩니다.
스택 영역(Stack Area)
- 메모리의 스택(Stack) 영역은 함수의 호출과 관계되는 지역 변수와 매개변수가 저장되는
영역입니다.
- 함수 안에서 선언된, 일반적인 변수를 통칭하며 함수가 종료될 때 저장되어 있던 메모리 값이
소멸됩됩니다.
힙 영역(Heap area)
- 사용자가 원하는 시점에 메모리를 할당하고 소멸하도록 할 수 있는 변수들이
할당되는 영역입니다.
오늘 저희가 눈여겨 보아야 할 곳은 힙 영역(Heap area)입니다.
c언어에서 변수를 선언하는 방법은 두 가지 방법이 있습니다.
정적 할당
ex) int a, int buffer[100];
사용하는 운영체제에 따라 각 데이터형에 약속된 기억 공간의 크기가 있고, 지정된 만큼
프로그램을 실행하는 프로세서에서 필요한 자원으로 할당시켜줍니다.
즉, 미리 변수의 기억공간을 할당받고 시작하는 할당 방법을 의미합니다.
정적 할당의 장점
- 해제하지 않음으로 인한 메모리 누수와 같은 문제를 신경 쓰지 않아도 됩니다..
정적 할당된 메모리는 실행 도중에 해제되지 않고, 프로그램이 종료할 때 알아서
운영체제가 메모리 공간을 회수합니다. -> 편합니다.
정적 할당의 단점
- 메모리의 크기가 프로그램 실행 전 결정되어 있어 프로그램 실행 도중에
크기를 변경할 수 없습니다.
- 스택에 할당된 메모리이므로
동적 할당에 비해 할당받을 수 있는 최대 메모리에 제약을 받습니다.
동적 할당
ex) int *i=(int *)malloc(sizeof((int));
c/c++언어에서 동적으로 할당된 메모리 공간은 프로그래머가 명시적으로
직접 해제해야 합니다.
c/c++에서 동적 할당을 하면 사용자가 해제하기 전까지는 메모리 공간이 계속
유지됩니다,
동적 할당은 메모리의 힙 영역(Heap area)에서 할당됩니다.
하지만 동적 할당을 할 때 프로그램이 정해진 힙 영역의 크기를 넘는 메모리
할당을 요구하면 할당되지 않습니다. 따라서 사용이 완료된 메모리 영역은
반납을 하는 것이 유리하기 때문에 프로그래머는 필요 없을 때
동적 할당을 해제하는 함수(free())를 사용해서 꼭 해제를 해야 합니다.
동적 할당의 장점
- 상황에 따라 원하는 크기만큼의 메모리가 할당되므로 효율적이며,
이미 할당된 메모리라도 정적 할당의 변수와는 다르게 언제든지 크기를
조절할 수 있습니다.
동적 할당의 단점
- 더 이상 사용하지 않을 때 명시적으로 메모리를 해제해 주어야 합니다.
- 동적 할당을 할 때는 프로그램이 종료되어도 메모리가 소멸되지 않으므로
꼭 프로그램의 종료 전 동적 할당 해제를 해주어야 한다는 단점이 있습니다.
동적 메모리 할당 순서
1. alloc류의 함수로 메모리를 할당합니다.
- malloc(), calloc(), realloc()
2. 프로그램에서 할당된 메모리를 사용합니다..
3. free() 함수를 사용하여 사용한(할당된) 메모리 공간을 해제합니다.
동적 할당 관련 함수
1. malloc()
2. calloc()
3. realloc()
4. free()
※다음의 함수들은 "stdlib.h"의 헤더 파일에 있습니다.
malloc()
- 힙 영역(Heap area)에서 단순히 메모리 할당만 해주는 함수
- malloc() 함수는 단순히 메모리만 할당하는 함수이기 때문에
어떠한 데이터 형을 저장하는지 예측할 수 없습니다.
예를 들어 4바이트를 할당하였을 경우 int형의 데이터를 저장하기 위해서 사용하는지, float형
데이터를 사용하려고 할당받은 것인지 컴퓨터는 예측할 수 없기 때문에 void 포인터를
반환하여 개발자가 알맞은 용도로 변환하여 사용할 수 있도록 만듭니다
realloc()
- 기존에 할당된 메모리의 크기를 바꿀 때 사용하는 함수입니다.
calloc()
- malloc() 함수와 같이 힙에서 메모리를 할당하며, 할당한 모든 값을 0으로 초기화
해주는 함수이다. 또한, 사용 형태가 조금 다릅니다.
-free()
- 할당한 메모리를 해제해주는 함수
메모리를 할당만 하고 해제해 주지 않는다면, 언젠가는 메모리가 부족한
현상이 발생할 것이 입니다.
그러므로 할당된 메모리가 더 이상 필요하지 않을 경우 free함수를 이용하여
꼭 메모리를 해제시켜 줘야 합니다.
원리.
이러한 함수들은 메모리상에서 주소를 void*형으로 반환해주어
그 반환된 값을 타입 형 변환(Type casting)을 합니다.
그러면 포인터에 반환된 주소의 값이 정확하게 들어가게 되는
것입니다.
메모리 누수
메모리 누수는 말 그대로 물이 새듯이 메모리가 새는 것을 의미한다.
메모리 누수는 할당된 메모리가 더 이상 사용되지 않지만 해체되지 않았을 때
발생합니다.
1. 메모리 주소를 잃어버린 경우
2. free() 함수가 호출되어야 하는 상황에 호출되지 않은 경우
3. 메모리 주소가 손실된 경우
와 같이 위 상황들을 메모리가 누수된다고 합니다.
댕글링 포인터(Dangling pointer)
- 해제된 메모리 영역을 가리키고 있는 포인터를 말합니다.
만약 위 그림처럼 포인터가 동적 할당된 메모리의 주소를
가리키고 있다고 예를 들어봅시다.
포인터를 써서 여러 가지 일을 하고 free() 함수를 써줍니다.
그러면 메모리 상의 공간은 메모리 해제가 됩니다.
그런데 무엇이 문제일까요??
바로 포인터는 해제된 메모리의 공간을 아직도
가리킨다는 점입니다.
이는 잠재적 보안 위협이 될 수 있습니다.
댕글링 포인터 문제 해결 방법
1. 메모리 해제 후 포인터를 NULL로 설정한다.
2. 몇몇 런타임 시스템이나 디버깅 시스템은 해제된 메모리를 특별한
값으로 덮어쓴다.
3. 댕글링 포인터와 다른 문제들을 발견하기 위해 서드파티 도구를 이용한다.
위와 같은 방법들이 있는데
1번의 방법들이 가장 구현하기 쉬운 방법인 것 같습니다.
동적 할당의 활용
이렇게 메모리 구조와 동적 할당에 대해서
배웠지만 아직 동적 할당을 어떻게, 언제 써야 할지 감이 안 오시는 분들이 계실 겁니다.
동적 할당은 예를 들자면
같은 반 친구들의 평균 점수를 입력받아야 된다고 할 때
숫자 하나를 입력 받아 동적 할당을 하여 학생수와 정확하게 배열을 만들 수 있습니다.
CODEUP 같은 문제를 푸시거나 그러다 보면 굉장히 쓸 때가 많고 해킹을 할 때도 중요한 부분입니다.
(취약점이 많다) 잘 이해하고 넘어가시길 바랍니다.
긴 글 끝까지 읽어주셔서 감사합니다.
포스팅에 틀린 점이 있다면 꼭꼭 알려주세요.
'layer7' 카테고리의 다른 글
Layer7 10 과제 -리눅스 보고서- (0) | 2019.05.26 |
---|---|
Layer7 과제 08 -개인 프로젝트 보고서- (0) | 2019.05.25 |
Layer 7 07 과제 - 달팽이 배열 (0) | 2019.04.10 |
Layer 7 06 과제 -포인터 보고서 (0) | 2019.04.07 |
Layer 7 05 과제 - 함수 보고서 작성 (0) | 2019.04.07 |