본문 바로가기
Program/C++ MFC

[C++] 배열 new를 사용해 선언했지만 스칼라 delete로 삭제했습니다. 발생 이유와 해결 방법

by 냠만 2024. 5. 29.

[Memory leak현상]

C++에서는 C#에서와 달리 애플리케이션에서 주기적으로 가비지컬렉터(GC.Collect)에 설정된 배열에 데이터가 없더라도 이미 사용 중인 메모리 공간으로 인식하여 프로그램을 종료해도 메모리가 해제되지 않는 상황이 발생합니다
어떻게 보면 메모리를 딱 필요한 만큼만 사용하기 때문에 효율적이고 빠르다고 생각할 수 있으나 개발자 입장에서는 매우 귀찮은 일이 아닐 수 없습니다.


메모리가 해제되지 않으면 PC를 재부팅하지 않는 이상 메모리 주소값이 동결되어버리는 leak현상이 발생되고 해당 현상이 반복되면 시스템 효율에 큰 이상점을 발생시키게 되고 결과적으로 프로그램의 성능을 떨어뜨리는 역할을 하게 됩니다.

해당 현상이 발생되지 않도록 선언된 메모리 영역을 해제시켜줘야 하는데요. 그럴때 사용하는 게 delete 함수입니다.


[delete 함수와 delete[] 함수의 차이]

delete 함수는 MSDN에 두가지 구문 변형이 있다고 소개되어 있습니다. (단일 개체, 개체 배열)
delete 함수는 단일 개체에 사용되고, delete[] 함수는 개체 배열에 사용됩니다.

C++에서 일반적으로 배열을 선언할 때 int* 배열이름 = new int 형식으로 선언하게 되는데요.
해당 배열을 시작 포인트를 가지고 크기를 알고있으면 메모리에 접근할 수 있기 때문에 배열을 첫 인자를 가리키는 포인터를 선언함으로써 메모리 사용 효율을 높이는 구조로 되어있습니다.

이 부분에서 문제가 발생되는데요. 메모리 해제 방식에 차이가 있기 때문입니다.
배열을 선언할 때 첫 인자 앞부분 메모리에 배열의 사이즈를 입력해 놓는데요.
delete는 해당 주소값에 접근해서 메모리를 한번 해제하지만 delete[]는 해당 주소값에 접근해서 메모리를 배열 사이즈만큼 여러 번 해제하기 때문입니다.

실제로 테스트를 진행해보면 배열데이터에 delete를 사용하면 소멸자가 한 번만 호출되어 배열을 첫 인자의 메모리 부분만 해제된 걸 확인할 수 있습니다.


[메모리 해제 테스트]


위와같이 입력받은 메모리 개수만큼 배열을 생성하고 해제하는 방법을 코드로 구현해서 테스트를 진행해 봅니다.

 

1번 방법이 스칼라 삭제 방법이고 2번 방법이 배열 삭제 방법입니다.

배열 5개를 입력받아 생성자와 소멸자 호출 횟수를 비교해 보면 스칼라 삭제에서는 소멸자가 한 번만 호출된 걸 확인할 수 있습니다.

반대로 2번 배열삭제에서는 정상적으로 생성자 호출 횟수와 동일한 횟수의 소멸자가 호출된걸 확인할 수 있습니다.

 

 

 

visual studio에서 자체적으로 오류메시지를 띄워주긴 하지만 크리티컬 한 부분이 아니라고 판단하는지 빌드는 정상적으로 진행됩니다. 이런 실수가 쌓이면 프로그램이 조금만 켜져 있어도 심각한 성능저하를 느낄 수 있기 때문에 항상 주의하면서 개발하는 습관을 가져야 될 것 같습니다.