들어가기 전에
각각 사이다와 콜라가 들어있는 컵 두 개를 떠올려봅시다. 만약 사이다와 콜라를 각각 다른 컵으로 바꿔 담고 싶으면 어떻게 해야 할까요? 교환을 도와줄 수 있는 새로운 컵이 잠시 필요하겠죠. 그렇다면 메모리에 저장된 값들을 교환할 때도 이와 비슷하게 할 수 있을까요?
학습 목표
메모리에 저장된 두 값을 교환하는 코드를 작성할 수 있습니다.
핵심 단어
- 스택
- 힙
- 포인터
강의 듣기
들어가기 전에
각각 사이다와 콜라가 들어있는 컵 두 개를 떠올려봅시다. 만약 사이다와 콜라를 각각 다른 컵으로 바꿔 담고 싶으면 어떻게 해야 할까요? 교환을 도와줄 수 있는 새로운 컵이 잠시 필요하겠죠. 그렇다면 메모리에 저장된 값들을 교환할 때도 이와 비슷하게 할 수 있을까요?
학습 목표
메모리에 저장된 두 값을 교환하는 코드를 작성할 수 있습니다.
핵심 단어
강의 듣기
아래와 같은 코드가 있습니다. 함수 swap은 정수 a와 b를 입력받아 그 값을 바꾸는 일을 수행합니다.
main 함수에서는 x에 1, y에 2를 입력하고 swap 함수를 통해 그 두 값을 바꾸려고 하고 있습니다.
과연 의도대로 잘 바뀌어서 출력이 될까요?
#include <stdio.h>
void swap(int a, int b);
int main(void)
{
int x = 1;
int y = 2;
printf("x is %i, y is %i\n", x, y);
swap(x, y);
printf("x is %i, y is %i\n", x, y);
}
void swap(int a, int b)
{
int tmp = a;
a = b;
b = tmp;
}
위 코드를 컴파일하고 출력해보면 우리 의도와는 다르게 swap 함수를 거친 후에도 x와 y의 값이 바뀌지 않은채 그대로 출력됨을 알 수 있습니다.
사실 swap 함수는 교환 작업을 제대로 수행하고 있는데요, 문제는 교환하는 대상이 x, y 그 자체가 아닌 함수 내에서 새롭게 정의된 a, b라는 것이었습니다.
a와 b는 각각 x와 y의 값을 복제하여 가지게 됩니다. 서로 다른 메모리 주소에 저장되는 것이죠.
아래 그림에서와 같이 메모리 안에는 데이터 저장되는 구역이 나뉘어져 있습니다.
머신 코드 영역에는 우리 프로그램이 실행될 때 그 프로그램이 컴파일된 바이너리가 저장됩니다.
글로벌 영역에는 프로그램 안에서 저장된 전역 변수가 저장됩니다.
힙 영역에는 malloc으로 할당된 메모리의 데이터가 저장됩니다. 그리고 스택에는 프로그램 내의 함수와 관련된 것들이 저장됩니다.
이를 바탕으로 다시 생각해보면, 위의 코드에서 a, b, x, y, tmp 모두 스택 영역에 저장되지만 a와 x, b와 y는 그 안에서도 서로 다른 위치에 저장된 변수입니다.
따라서 a와 b를 바꾸는 것은 x와 y를 바꾸는 것에 아무런 영향도 미치지 않는 것이죠.
따라서 아래 그림 및 코드와 같이 a와 b를 각각 x와 y를 가리키는 포인터로 지정함으로써 이 문제를 쉽게 해결할 수 있습니다.
#include <stdio.h>
void swap(int *a, int *b);
int main(void)
{
int x = 1;
int y = 2;
printf("x is %i, y is %i\n", x, y);
swap(&x, &y);
printf("x is %i, y is %i\n", x, y);
}
void swap(int *a, int *b)
{
int tmp = *a;
*a = *b;
*b = tmp;
}
생각해보기
메모리 영역을 다양하게 나누는 이유는 무엇일까요?
comment
메모리 영역을 다양하게 나누는 이유는 한정된 메모리를 효율적으로 관리하기 위함이다.
한정된 메모리를 효율적으로 관리, 메모리 오류를 쉽게 감지하기 위함
영역을 분리해 서로에게 영향을 주지 않으며,
접근법에 따른 방식을 적용하기위해서
메모리는 크게 텍스트 영역, 데이터 영역, 힙, 스택 4개의 구조로 나뉜다.
이는 한정된 메모리를 효율적으로 관리하기 위함으로, 각 성격과 목적에 따라 나누어 사용한다.
메모리가 여유로운 상태라면 굳이 메모리를 관리해야 할 필요가 없다고 생각할 수도 있으나, 메모리가 매우 제한되어 있다면, 적은 메모리를 가지고 최대한 효율적인 사용을 위하여 관리를 해주어야 할 필요가 있다.
예컨데, 군용(사격 통제 장치) 또는 인공위성 및 우주(행성) 탐사선 등, 제한된 메모리를 극단적인 효율성을 가지고 운용해야 할 필요가 있다.
상황, 용도에 맞게 나누어서 사용하려고 나눈 것이라고 생각합니다
Splitting memory into different areas is important because :
1. Resource Efficiency : By putting only what's needed in each area, we use memory more efficiently.
2. Security: We can protect important parts and find problems easier.
3. Error Detection: It's easier to spot and fix mistakes.
4. Virtual Memory Management: Helps the operating system manage memory better.
5. Performance Improvement : Each area can be optimised for specific tasks, making things run faster.
Splitting memory like this makes programs run better, safer, and faster.
메모리의 효율적 사용 때문
메모리는 유한하니까 더 효율적으로 사용하기 위해 다양한 영역을 나눈다.
효율적인 활용을 위해서
그런데 아직 힙 영역과, 스택 영역을 나누는 이유는 정확히 모르겠음
- 효율적인 활용
: 메모리를 여러 영여긍로 나누면 각 영역을 특정 목적에 맞게 사용할 수 있음
- 보안
:메모리를 나누면 중요한 데이터나 코드를 안전하게 저장하는 데 도움이 됨
- 오류 검출 및 디버깅
: 메모리를 세분화하면 메모리 오류를 쉽게 감지하고 디버그할 수 있음
- 가비지 컬렉션
: David가 말했던 CS50의 get_string을 비롯한 여러 함수 중 하나인데 가비지 컬렉션을 사용하여 메모리 누수를 방지함
- 성능 최적화
: 메모리 영역을 나누면 데이터 접근 패턴을 최적화할 수 있음
- 다중 프로세스 및 스레드 지원
: 다중 프로세스 또는 스레드 환경에서 메모리를 나누면 각 프로세스 또는 스레드 간의 충돌을 방지하고, 데이터 공유를 관리하는 데 도움이 됨
효율적인 관리를 위해
서로 침범하면 오류가 생기니까
메모리를 역할에 맞게 구분하여 효율적으로 관리하려고
메모리를 역할에 맞게 구분하여 효율적으로 관리하기 위해서이다.
각 상황에 맞게 메모리를 해제하고, 활용하고를 통해서 더 효율적인 사용을 위하여
메모리를 효율적으로 관리하기 위해
각각의 상황에 맞게 메모리 영역을 다르게 사용하여 메모리를 더욱 효율적으로 사용하기 위해서인 것 같습니다.
나: "구분이 되어 있어야 하드웨어 측면에서 접근하기 훨씬 수월하기 때문 아닐까?"
ChatGPT: "메모리 영역을 다양하게 나누는 이유는 효율성, 보안, 메모리 관리 등 다양한 이유로 설계되었습니다. 스택을 사용하여 지역 변수와 함수 호출을 관리하고, 힙을 사용하여 동적 메모리 할당을 수행하며, 데이터 세그먼트와 코드 세그먼트를 사용하여 데이터와 명령어를 분리하여 관리합니다. 이러한 메모리 영역의 구분은 프로그램의 실행과 관련된 다양한 요구사항을 충족시키고 메모리 관리를 효율적으로 수행할 수 있도록 도와줍니다."
변하지 않는 데이터, 자주 생성되고 삭제되는 데이터, 사이즈가 상황에 따라 달라질 수 있는 데이터 등 용도에 맞게 사용하여
메모리의 시간적, 공간적 사용 효율을 최대화하기 위함입니다.