Search Results for '메모리 할당'

1 POSTS

  1. 2007.01.27 WIPI C의 메모리 할당: 과유불급

WIPI C의 메모리 할당: 과유불급

Posted 2007. 1. 27. 11:18
WIPI C는 핸드폰 환경에서 C 언어로 응용 프로그램을 제작하기 위한 국내 표준 모바일 환경입니다.  메모리 할당해제, LCD 제어, 이벤트 처리, 네트워크 접속 등에 관련된 각종 API도 표준으로 정하고 있습니다. 최근에 WIPI C로 간단한 프로젝트를 할 일이 있었는데, 이 과정에서 WIPI C의 느낀 문제점을 정리해 보려 합니다. (이전 글인 "WIPI 플랫폼에 포팅하기"에서 메모리 할당에 대해 이야기한 적이 있습니다.)

*** WIPI C에서 메모리 할당/해제

WIPI C는 대부분의 메모리가 제약된 임베디드 환경에 맞추어서 메모리 컴팩션(compaction)을 기본으로 지원합니다. 기존의 malloc/free 방식은 아무리 잘 구현해도 외부 단절화(external fragmentation) 현상으로 인해 메모리를 할당 받을 수 없는 문제를 피해갈 수 없기 때문입니다.

WIPI C는 MC_knlAlloc()/MC_knlCalloc() 함수를 통해 메모리를 할당 받고 MC_knlFree() 통해 메모리를 해제합니다. 이 때 할당 받은 메모리는 포인터가 아닌 메모리 식별자(M_Uint32 타입)입니다. MC_GETDPTR()라는 매크로를 이용하면 해당 식별자에서 메모리 포인터를 얻어올 수 있습니다. 이렇게 간접 참조를 사용하는 이유는, 컴팩션이 일어나면 메모리 포인터가 언제든지 바뀔 수 있기 때문입니다. 컴팩션이 일어날 수 있는 시점 이후에는 항상 MC_GETDPTR()를 이용해 새로 포인터를 얻어오는 방식이죠.

응용 프로그램 개발자가 이 규칙을 제대로 준수하면, malloc/free 구현에서 발생하는 외부 단편화 현상도 없애고 메모리를 매우 효율적으로 이용할 수 있으므로 좋은 일이 될 것입니다. 하지만 ‘개발자 편의성’이라는 측면에서 보면 이 방식은 너무 귀찮습니다. MC_knlAlloc()/MC_knlCalloc()을 통해 메모리를 한 번 할당해 올 때마다, 컴팩션이 일어날 수 있으므로 이전에 얻어놨던 포인터가 전부 무효가 됩니다. 한 번이라도 포인터를 새로 얻어오지 않은 지점이 있으면 잠재적인 버그로 이어지니 무시무시한 것이지요.

불편함은 여기에서 그치지 않습니다. M_Int32 foo(M_Byte *str, M_Int32 len)과 같은 함수를 구현한다고 생각해 봅시다. 만약 foo라는 함수를 작성할 때 새로 메모리를 할당 받을 필요가 있으면 어떻게 될까요? 우리는 인자로 넘어온 str이 동적 할당된 메모리에서 온 것이지 정적 할당된 메모리에서 온 것인지 알 방법이 없습니다. 만약 동적으로 할당된 메모리에서 왔다면 우리가 foo() 함수 내부에서 메모리를 새로 할당 받는 순간 str은 더 이상 유효한 포인터가 아니게 될지도 모릅니다.


M_Int32 foo(M_Byte *str, M_Int32 len)
{
    M_Uint32 hnd;
    hnd = MC_knlAlloc(CONSTANTS); /* 이 시점에서 str은 더 이상 유효한 포인터가 아님 */
    // ...
}


물론 여기에 대한 대안은 포인터 대신에 식별자를 넘기도록 수정하는 것입니다. M_Int32 foo(M_Uint32 strHnd, M_Int32 len)와 같이 수정하면 foo() 함수 내부에서 새로 메모리를 할당 받더라도 변경된 포인터를 얻어올 수 있을 것입니다. 하지만 이 방식에서는 첫 번째 인자가 M_Byte *라는 타입 정보가 날라가는 효과가 있습니다. 함수만 봐서는 인자로 어떤 타입을 받는지 알 수 없는 거죠.

나름 좋은 의도로 출발한 제약 사항이라도 개발자의 편의를 심각하게 저해하는 경우 역효과를 일으킬 수 있습니다. WIPI C 개발자는 동적 할당의 제약 사항을 피하고자 되도록이면 동적 할당을 피하고, 정적 할당을 사용하는 것이 첫 번째입니다. 동적 할당에서 포인터를 매번 새로 얻어오는 번거로움을 피하고자, 포인터가 변경되지 않는 정적 할당을 필요보다 훨씬 더 많이 사용하게 되는 것이지요.

이 방식이 극단으로 가면 큰 메모리 블록은 할당 받아서 내부적으로 malloc/free 함수를 구현해 쓸 수도 있는 일입니다. WIPI C 플랫폼이 그토록 피하고자 했던 일을 개발자가 오히려 추가적인 수고를 들여서라도 하려고 하는 것입니다. 욕심이 지나치면 일을 망친다고 하였습니다. ’개발자 편의성’을 무시하고 무리한 일을 요구하면, 그 의도가 아무리 좋아도 일을 망치는 법이 아닐까 싶습니다.