0Pricing
C Academy · 강의

해제하고 누수 방지하기

메모리를 올바르게 정리해 보세요.

해제하고 누수 방지하기은(는) CoddyKit의 무료 C Academy 강의입니다. 이것은 4개 중 4번째 강의입니다. 아래에서 전체 강의를 무료로 읽을 수 있으며, 내장 코드 에디터와 24/7 AI 튜터와 함께 브라우저에서 직접 실습할 수 있습니다. 이 강의는 C Academy 학습 경로의 일부이며, 진행 상황이 웹과 CoddyKit 앱에 동기화됩니다. C Academy 강의에는 총 4개의 강의가 포함되어 있습니다.

모든 malloc에는 free가 필요합니다

힙 메모리는 free로 해제할 때까지 예약된 상태로 남습니다. 블록을 해제하지 않은 채 그 블록을 가리키는 유일한 포인터를 잃으면 메모리 누수가 발생합니다.

누수는 시간이 지나면서 쌓여 장시간 실행되는 프로그램의 메모리를 고갈시킬 수 있습니다.

int *a = malloc(100 * sizeof(*a));
/* ... use a ... */
free(a);

free가 실제로 하는 일

free(p)는 블록을 할당자에게 돌려주어 재사용할 수 있게 합니다. 하지만 p 자체의 값은 바꾸지 않습니다.

free한 뒤에도 p는 이제 유효하지 않은 이전 주소를 가리킵니다. 이 포인터에 접근하면 정의되지 않은 동작이 발생합니다.

free(p);
/* p is now a dangling pointer */

댕글링 포인터의 함정

해제한 뒤 포인터를 사용하면 use-after-free 버그가 발생합니다. 우연히 작동하는 것처럼 보이다가 데이터를 손상시키거나 예측할 수 없이 중단될 수 있습니다.

간단한 방어 방법은 해제 직후 포인터를 NULL로 설정하는 것입니다.

free(a);
a = NULL;   /* now misuse is a clean NULL deref, easier to catch */

이중 free는 정의되지 않은 동작입니다

같은 블록에 free를 두 번 호출하면 할당자의 내부 상태가 손상되고, 프로그램이 중단되는 경우가 많습니다.

첫 번째 free 후 포인터를 NULL로 설정하면 도움이 됩니다. free(NULL)은 명시적으로 안전하며 아무 작업도 하지 않기 때문입니다.

free(a);
a = NULL;
free(a);   /* free(NULL) is a harmless no-op */

malloc한 것만 free하십시오

free에는 malloc, calloc, realloc에서 반환된 포인터만 전달하십시오.

스택 변수의 주소, 문자열 리터럴, 또는 블록 중간을 가리키는 포인터를 해제하면 정의되지 않은 동작이 발생합니다.

int x = 5;
/* free(&x);   WRONG: x is on the stack */
int *p = malloc(sizeof(int));
free(p);        /* correct */

이른 반환으로 인한 누수

흔히 발생하는 누수는 다음과 같습니다. 메모리를 할당한 뒤 오류 처리 경로에 들어가 해제하기 전에 반환하는 것입니다. 그러면 해당 블록을 잃게 됩니다.

메모리를 소유한 모든 종료 경로에서 먼저 메모리를 해제하도록 하십시오.

int *a = malloc(n * sizeof(*a));
if (something_failed) {
    free(a);   /* don't forget this before returning */
    return -1;
}

깔끔하게 할당하고 해제하는 프로그램

이 프로그램은 모든 경로에서 메모리를 할당하고 사용한 뒤 해제하므로 아무것도 누수되지 않습니다.

#include <stdio.h>
#include <stdlib.h>

int main(void) {
    int n = 4;
    int *a = malloc(n * sizeof(*a));
    if (!a) return 1;
    for (int i = 0; i < n; i++) a[i] = i + 1;
    int sum = 0;
    for (int i = 0; i < n; i++) sum += a[i];
    printf("%d\n", sum);
    free(a);
    a = NULL;
    return 0;
}

중첩된 할당 해제

블록이 다른 블록을 가리키는 포인터를 포함한다면 먼저 내부 블록을 해제한 다음 외부 블록을 해제하십시오.

외부 블록을 먼저 해제하면 내부 블록의 주소를 잃어버려 내부 블록이 누수됩니다.

for (size_t i = 0; i < rows; i++)
    free(grid[i]);   /* free each row first */
free(grid);          /* then the array of pointers */

블록마다 소유자 하나

각 할당을 소유하고 해제할 책임이 있는 코드 부분을 정하십시오.

두 포인터가 같은 블록을 가리키고 둘 다 해제하면 이중 해제가 발생합니다. 소유권을 명확히 하면 이를 방지할 수 있습니다.

도구로 누수 감지하기

누수를 눈으로 직접 찾을 필요는 없습니다. valgrind나 AddressSanitizer 같은 도구가 줄 번호와 함께 누수 및 잘못된 해제를 보고합니다.

-g 옵션을 사용해 컴파일한 뒤 도구로 실행하면 정확히 무엇이 해제되지 않았는지 확인할 수 있습니다.

/* gcc -g -fsanitize=address prog.c && ./a.out */
/* or: valgrind --leak-check=full ./a.out */

설정한 순서의 반대로 해제하기

신뢰할 수 있는 습관이 하나 있습니다. 함수에서 여러 리소스를 확보했다면 확보한 순서의 반대로 해제하십시오.

이 방식은 의존성이 만들어진 순서를 따르므로 정리 과정을 예측 가능하게 유지해 줍니다.

char *buf = malloc(64);
int  *idx = malloc(64 * sizeof(int));
/* ... use them ... */
free(idx);   /* free last-acquired first */
free(buf);

빠른 확인

메모리 해제에 대한 이해도를 확인해 보십시오.

복습

모든 코드 경로에서 모든 할당에 정확히 하나의 free를 대응시키십시오.

해제한 뒤 포인터를 NULL로 설정하여 댕글링 포인터와 이중 해제를 피하십시오. 중첩된 할당은 내부부터 해제하고, 각 블록에 소유자를 하나씩 지정하며, valgrind 또는 ASan을 사용해 누수를 찾아내십시오. 이제 동적 배열을 다루는 데 필요한 도구를 모두 익혔습니다.

자주 묻는 질문

“해제하고 누수 방지하기” 강의는 무료인가요?

네 — “해제하고 누수 방지하기” 전체 내용을 이 웹사이트에서 무료로 읽을 수 있습니다. 인터랙티브하게 실습하려면(내장 코드 에디터와 24/7 AI 튜터), CoddyKit PRO로 업그레이드하면 C Academy 강의 전체를 잠금 해제할 수 있습니다. C Academy 강의에는 총 4개의 강의가 포함되어 있습니다.

“해제하고 누수 방지하기”에서 뭘 배우나요?

메모리를 올바르게 정리해 보세요. 브라우저에서 직접 실행하는 실습 코드로 C Academy을(를) 배우며, 24/7 AI 튜터가 강의를 진행하면서 질문에 답변해줍니다.

C Academy을(를) 시작하는 데 경험이 필요한가요?

사전 경험은 필요하지 않습니다. CoddyKit의 C Academy은(는) 초급자부터 고급 학습자까지를 위해 구성되어 있으므로, 여기서 시작하거나 처음부터 시작할 수 있으며 자신의 속도대로 진행할 수 있습니다. 이것은 4개 중 4번째 강의입니다.

“해제하고 누수 방지하기” 강의는 얼마나 걸리나요?

대부분의 CoddyKit 강의는 약 5~10분이 소요됩니다. 각 강의는 간결하고 인터랙티브하여 꾸준한 진행이 가능하며, 웹과 앱에서 중단한 부분부터 바로 시작할 수 있습니다.

이 C Academy 강의에서 코드를 작성하고 실행할 수 있나요?

네. 모든 C Academy 강의에는 내장 코드 에디터가 포함되어 있으므로, 브라우저에서 바로 실제 코드를 작성하고 실행한 후 즉시 AI 피드백을 받을 수 있습니다 — 로컬 설정이 필요 없습니다.

이 강의의 모든 강의

  1. 배열 할당하기
  2. realloc으로 확장하기
  3. 재사용 가능한 벡터 형식
  4. 해제하고 누수 방지하기
← C Academy(으)로 돌아가기