[CS50] 메모리 - 메모리 할당과 해제

TIL

메모리를 할당한 후에 저장한 값이 필요 없어지고 나면 어떻게 해야 할까?

유한한 메모리를 효과적으로 관리하기 위해 할당한 메모리를 어떻게 관리해야 하는지 알아보자.

메모리 해제의 필요성

malloc 함수를 이용하여 메모리를 할당한 후에는 free 함수를 이용하여 메모리를 해제해야 한다.

그렇지 않으면 메모리에 저장한 값은 쓰레기 값으로 남게 되어 메모리 용량의 낭비가 발생하는데, 이러한 현상을 메모리 누수(Memory Leak)라고 한다.

 

문제가 있는 코드

다음 코드를 살펴보자.

#include <stdlib.h>

void f(void)
{
    int *x = malloc(10 * sizeof(int));
    x[10] = 0;
}

int main(void)
{
    f();
    return 0;
}
  • 함수 f는 포인터 x에 int형의 크기(4바이트) × 10 = 40바이트 메모리를 할당
  • x의 10번째 값으로 0을 할당

이 코드를 valgrind로 검사하면 버퍼 오버플로우와 메모리 누수에 관한 에러를 확인할 수 있다.

 

valgrind란?
리눅스 기반의 오픈소스 DBI 도구로, 소프트웨어의 메모리 사용을 분석하고 메모리 누수를 감지하는 프로그래밍 도구다.

 

문제점 1: 버퍼 오버플로우

int *x = malloc(10 * sizeof(int));  // 10개의 int형 배열 생성
x[10] = 0;  // 배열의 11번째에 접근 → 오류 발생

 

배열의 인덱스는 0부터 9까지만 존재하는데, 존재하지 않는 11번째 인덱스(x[10])에 접근하려고 하여 버퍼 오버플로우(Buffer Overflow)가 발생한다.

 

메모리 상황:

할당된 메모리: x[0] x[1] x[2] ... x[9]
                                        ↓
접근 시도:                              x[10] ← 범위 초과!

 

문제점 2: 메모리 누수

void f(void)
{
    int *x = malloc(10 * sizeof(int));
    x[10] = 0;
    // free(x)가 없음!
}

포인터 x를 통해 할당한 메모리를 해제하지 않아 메모리 누수가 발생한다.

 

메모리 누수 과정:

1. f() 호출 → 메모리 할당 (40바이트)
2. f() 종료 → x 포인터는 사라짐
3. 할당된 40바이트는 여전히 메모리에 남음
4. 접근할 방법이 없는 쓰레기 메모리가 됨

 

함수가 여러 번 호출되면 메모리 누수가 누적된다

f() 호출 1회 → 40바이트 누수
f() 호출 100회 → 4000바이트 누수
f() 호출 100만회 → 약 38MB 누수

 

수정된 코드

위의 오류를 해결한 코드는 다음과 같다.

#include <stdlib.h>

void f(void)
{
    int *x = malloc(10 * sizeof(int));
    x[9] = 0;  // 유효한 인덱스로 변경
    free(x);   // 메모리 해제
}

int main(void)
{
    f();
    return 0;
}
  • x[10] → x[9]: 유효한 인덱스 사용
  • free(x) 추가: 메모리 해제

 

malloc과 free 사용 패턴

기본 패턴

// 1. 메모리 할당
int *ptr = malloc(size);

// 2. NULL 체크
if (ptr == NULL)
{
    return 1;  // 할당 실패
}

// 3. 메모리 사용
// ... 작업 수행 ...

// 4. 메모리 해제
free(ptr);

 

실전 예제

#include <stdlib.h>
#include <string.h>

int main(void)
{
    // 문자열 복사
    char *source = "Hello";
    char *copy = malloc(strlen(source) + 1);

    if (copy == NULL)
    {
        return 1;
    }

    strcpy(copy, source);

    // 사용 후 해제
    free(copy);

    return 0;
}

 

메모리 관리 규칙

규칙 1: malloc과 free는 짝

malloc → 반드시 free

 

규칙 2: 이중 해제 금지

free(ptr);
free(ptr);  // ❌ 위험!

 

규칙 3: 해제 후 사용 금지

free(ptr);
ptr[0] = 1;  // ❌ 위험! (dangling pointer)

 

규칙 4: NULL 체크

int *ptr = malloc(size);
if (ptr == NULL)
{
    // 에러 처리
}

 

valgrind 사용법

# 컴파일
gcc -g memory.c -o memory

# valgrind로 검사
valgrind ./memory

 

// 출력 예시
==1234== Invalid write of size 4
==1234==    at 0x...: f (memory.c:6)
==1234== 40 bytes in 1 blocks are definitely lost

 

연습 문제

Q. 다음 코드의 문제점을 찾고 수정하시오.

void process_data(void)
{
    int *data = malloc(100 * sizeof(int));
    data[100] = 42;

    if (data[0] == 0)
    {
        return;
    }

    free(data);
}

 

문제점:

  1. 버퍼 오버플로우
  2. data[100] = 42; // 인덱스는 0~99까지만 유효
  3. 조건부 메모리 누수
  4. if (data[0] == 0) { return; // free(data) 실행 안 됨 }

 

수정된 코드:

void process_data(void)
{
    int *data = malloc(100 * sizeof(int));

    // NULL 체크 추가
    if (data == NULL)
    {
        return;
    }

    // 유효한 인덱스 사용
    data[99] = 42;

    // 조건문 전에 메모리 해제 또는
    // 모든 경로에서 해제 보장
    if (data[0] == 0)
    {
        free(data);  // 해제 추가
        return;
    }

    free(data);
}

 

더 나은 방법 (Early Exit 패턴):

void process_data(void)
{
    int *data = malloc(100 * sizeof(int));

    if (data == NULL)
    {
        return;
    }

    data[99] = 42;

    if (data[0] != 0)
    {
        // 작업 수행
    }

    // 모든 경로가 여기로 도달
    free(data);
}

 

핵심
- 모든 할당은 반드시 해제
- 유효한 인덱스만 접근
- 모든 실행 경로에서 메모리 해제 보장

'TIL' 카테고리의 다른 글

[CS50] 메모리 - 파일 입출력  (0) 2025.11.08
[CS50] 메모리 - 메모리 교환, 스택, 힙  (0) 2025.11.08
[CS50] 메모리 - 문자열 복사  (0) 2025.11.08
[CS50] 메모리 - 문자열 비교  (0) 2025.11.07
[CS50] 메모리 - 문자열과 메모리  (0) 2025.11.07
'TIL' 카테고리의 다른 글
  • [CS50] 메모리 - 파일 입출력
  • [CS50] 메모리 - 메모리 교환, 스택, 힙
  • [CS50] 메모리 - 문자열 복사
  • [CS50] 메모리 - 문자열 비교
고견
고견
개발 자국 남기기
  • 고견
    개발자국
    고견
  • 전체
    오늘
    어제
    • 분류 전체보기 (157) N
      • Frontend (29)
        • Next.js (16)
        • JavaScript (7)
      • CS (19) N
        • 자료구조 (9)
        • 알고리즘 (5)
        • 운영체제 (4) N
        • 네트워크 (1) N
      • TIL (93)
      • Dev Log (16)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    emotion diary
    자료구조
    useState
    cs50
    C
    문자열
    Pages Router
    함수 타입
    클래스
    트러블 슈팅
    ai 감성 일기장
    CS
    Spa
    제네릭
    인터페이스
    react
    Next.js
    Trouble Shooting
    알고리즘
    App Router
    바닐라 자바스크립트
    배열
    typescript
    memory
    javascript
    generic
    페이지 라우터
    앱 라우터
    algorithm
    타입 좁히기
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.5
고견
[CS50] 메모리 - 메모리 할당과 해제
상단으로

티스토리툴바