메모리관리에 관하여

jiho·2020년 2월 23일
0

C#

목록 보기
4/4

c++17을 공부 중 괜찮고 도움될 만한 내용이 있어서 따로 기록하겠습니다.

커스텀 메모리관리

c++에서는 기본으로 제공하는 메모리 할당 기능만으로 대부분의 일을 처리할 수 있습니다.
new, delete 를 말합니다. 현재 메모리에서 사용할 수 있는 공간을 관리하고, 다쓴 메모리를 해제하는데 필요한 모든 작업을 수행합니다.

리소스가 상당히 부족하거나 메모리 관리와 같은 특수한 작업을 수행할 때는 메모리를 직접 다뤄야 할 수도 있다. 핵심은 클래스에 큰 덩어리 메모리를 할당해놓고 필요할 때마다 잘라쓰는데 있습니다.

그렇다면 직접 관리하면 뭐가 좋을가요? 오버헤드를 좀 더 줄일 수 있습니다. 여기서 오베헤드란 new로 메모리를 할당하면 현재 프로그램에서 얼마나 할당했는지 기록하는데 필요한 공간을 말합니다. 이렇게 기록해둬야 delete를 호출할 때 딱 필요한 만큼 해제할 수 있습니다.
대부분 객체를 다룰 때 이 오버헤드는 할당한 공간에 비해 아주 작아서 문제되지않지만 크기가 작은 객체가 많거나 객체의 수가 엄청나게 많을 때는 이러한 오버헤드가 상당한 영향을 미칩니다.

메모리를 직접 다룰 때 객체크기를 사전에 알고 있다면 객체 크기를 관리할 공간을 줄 일 수 있습니다. 크기가 작은 객체가 아주 많으면 이렇게 절약한 효과가 상당합니다. 아마 대표적으로 네크워크 패킷을 추상화해서 사용할 경우 유용할 것 같네요.

가비지 컬렉션

메모리를 정상상태로 유지하기 위한 최후의 보루는 가비지 컬렉션입니다. 가비지 컬렉션을 제공하는 환경이라면 프로그래머가 객체에 할당된 메모리를 직접 해체할 일은 거의 없습니다. 더 이상 참조하지 않는 객체는 런타임 라이브러리에 의해 일정한 시점에 자동으로 해제됩니다.

C++는 자바나 C#과 달리 가비지 컬렉션이 기본으로 제공되지 않는다. 최신 버젼의 C++는 스마트 포인터로 메모리를 관리해서 나아졌지만, 예전에는 new, delete를 이용하여 객체 수준에서 직접 메모리를 관리해야했다. shared_ptr와 같은 스마트 포인터는 가비지 컬섹션과 상당히 비슷한 방식으로 메모리를 관리합니다. 어떤 리소스를 참조하든 shared_ptr가 삭제되면 일정 시간안에 그 포인터가 가리키던 리소스도 제거된다.

가비지 컬렉션을 구현하는 기법 중 mark and sweep란 알고리즘이 있습니다. 이 방식에 따르면 가비지 컬렉터가 프로그램에 있는 모든 포인터를 주기적으로 검사한 뒤 여기서 참조하는 메모리를 계속 사용하고 있는지 여부를 표시합니다. 한 주기가 끝날 시점에 아무런 표시가 되지 않은 메모리는 더 이상 사용하지 않는 것으로 간주하고 해제합니다.

모든 어플리케이션에 가비지 컬렉션이 적합하는 것은 아닙니다. 단점 몇가지를 소개하면 다음과 같습니다.

  • 가비지 컬렉터가 작동하는 동안 프로그램이 멈출 수 있다.(stop to world)
  • 가비지 컬렉터가 있으면 소멸자가 비결정적으로(non-deterministically)호출된다. 객체는 가비지 컬렉터에서 처리하기전에 제거되지 않기 때문에 객체가 스코프를 벗어나더라도 소멸자가 즉시 실행되지 않는다. 즉, 소멸자에서 처리하는 리소스 정리작업(파일을 닫거나 잠금을 해체하는 등과 같은)은 일정한 시점에 이르기 전에 실행되지 않는데, 얼마나 기다려야 할지 미리 알 수 없다.

문득 떠오른 비슷한 사례가 IOS개발을 하는 친구가 해당 프로시저가 종료되어도 타이머가 살아있는 문제를 말한 적이 있는데 이것도 유사한 가비지컬렉션의 비결정적인 소멸자 호출이 아닐가 생각이 듭니다.

profile
Scratch, Under the hood, Initial version analysis

0개의 댓글