본문 바로가기

Deveolper diary

C & C++? 메모리를 잡아라...

오늘은 팀장님과 숨막히는 (나만...팀장님은 귀찬은 하루였을 꺼라;;;)야근을 보내고 내일 발표를 위하여 어거지로 프로그램 CPR 해놨다. "무조건 시나리오 대로하고, 프로그램 죽으면 같이 죽자...." 라는 맨트와 VS2010의 컴파일러 성능, 윈도우의 메모리 관리 능력을 엿본 하루였다.


먼말인고 하니...API를 포팅하는 일이 여간 힘든게 아니라는걸 이번참에 깊이 께닫고 일단 포팅의 기본 개념인 "원 소스 보존"을 외치며, 정신없이 포팅했다. 


하지만 모든 메모리를 함수이전 또는 함수 윗 부분에 선언하는 C 스타일과는 틀리게 C++을 기반으로 하는 MFC는 class기반이라... 

대다수 많이 쓰는 부분이 머...Dialog class 이지... 사실 API 하면 대부분 다이얼로그다. 


오늘 팀장님게 배운 가르침은 컴파일러와 운영체제는 사람이 만든거라 믿지마라 ; 경험이 미천하니 어쩔 수 없었다 는 위로와 함께;


기본적으로 많이 사용하는 영역은 Stack영역이다. 이 Stack은 생각보다 속도가 매우 빠르다. 푸쉬와 팝을 하면서 느릴꺼 같지만 그건 함수 콜이나 인트럽트에 의한(루프나 분기) 컨텍스트 스위칭이 일어났을때 이야기고, 단순히 변수를 스텍 영역에 저장하는건 레지스트리 다음으로 빠르다고 알고있다.(머 100%는 아니지만 그 성능은 체감한 결과이다) 이유는 일단 다이렉트다. 물리적 메모리이든 가상 메모리이든 일단 주소 자체가 단일 주소이기 때문이다. 하지만 이놈이 2차원 배열을 틀면 이야기가 달라진다. 아 물론...메모리 상에서는 1차원으로 죽~잡겠지만 컴파일러는 귀엽게도 1차원 영역만 관리를 해준다는 것이다. 


물론 좀더 조사를 해봐야 겠지만 오늘 내가 배운 내용이다. 이 덕분에 2차원의 크기가 높아지면 높아질 수록 무슨일이 일어날지 모른다는 것! 그리고 재미있는 사실은 이 영역은 운영체제가 관리를 해줘야 하는데 이놈의 윈도우가 많이 바쁜지 관리가 느슨해 진다는것. 


A라는 클레스에 생각보다 많은 2차원 정적 변수를 멤버로 죽죽 잡아놓았을때 객체를 정적으로 생성했을때 객체를 선언함과 동시에 객체의 첫 주소 부터 멤버변수가 연속으로 선언된다. 이게 스텍의 특징! 하지만 이 메모리의 크기가 커지면 다름 메모리를 침범하게 된다는 것이다. 침범을 하고 있을 때는 프로그램에 이상을 느끼지 못할 수 도 있다. 하지만 메모리가 헤제가 되고나면 침범된 구역은 손상을 입고 결국 메인 클레스가 죽는 경우가 생긴다. 


이 문제는 생각보다 잡기가 까다로우며, 경험이 없으면 엉뚱한곳에서 해맬 수 밖에 없다. 왜냐하면 어디가 손상되는지는 그때 마다 다르기 때문이다. 


물론 정확한 이유를 검증해야 겠지만 이 이야기를 듣는 순간 아...젠장 그러네! 라는 생각이 절로 든다. 근데 사실 이론적인 논리상으로 동적보다는 정적을 선호 하며, 되도록이면 정적으로 사용하고 빨리 메모리를 반환하라는 말이 많다. 이렇게 하는 것이 자원관리를 좀더 심플하고 체계적으로 관리하는 방법이기 때문이다. 


하지만 많은 메모리를 잡는 클레스 일 경우, 정적선언 보다는 동적 선언을 해야한다. 동적으로 하게 되면 Hip영역에 지정이 되는데 이 영역은 연속적이지 않고 비어있는 메모리를 사용하기 때문에 기존 메모리를 사용하는 영역은 침범을 하지 않는다. 물론 이런 구조로 가는거 자체가 잘못된 프로그래밍이라는 것은 잘 알고 있다. -_-;;


Hip이 빠를거 같지만 느린 이유는 저 장점이 바로 단점이 되는 것이다. 메모리가 연속적이지 않고 분리되어 있으면 그것을 연결하기 위하여 연결 고리가 반드시 필요하다. 바로 Hip에 지정하게 되면 메모리 테이블이 생성이 되며, 가상주소를 이용하여 연속적이게 만든 후 실제로 참조할때는 그 가상 테이블을 따라서 실제 주소로 이동하게 된다. 바로 이 테이블을 한번 더 타게 하기 때문에 성능의 저하가 엄청나다. 


2년전 메트렙을 포팅하다가 변수의 크기를 몰라 모조리 동적으로 2차 3차원 배열을 잡은 적이 있는데 결과를 보려면, 20분 가량을 기다려야 하는 엄청난 일이 생겼었다. 누수도 장난 아니였었지.ㅋㅋㅋ 

당시 엄청난 선배(지금은 더욱더 엄청난...)님이 이거 다 파악해서 정적으로 선언해봐! 라는 말과 함께 이틀정도 작업하여 결과를 보니 3~5분으로 단축....ㅡㅡ;;


마지막으로 프로그램 정리 후 시간은 2~3분으로 줄었다. (CT Image 400장(512x512))


지금 생각 하는 것은 그때 메모리 공부를 좀더 깊게 했어야 하는 것이다. 다른 공부한다는 핑계로 너무 얕게 공부하고 넘긴 결과다. 


또한 오늘 다른팀에서 하는 스터디에서 멀티 스레드 부분에 매우 깊게 운영체제에 들어가는 것을 몇 분이지만 들을 수 있었다. 

학교에서 분명히 배운건데 기억이 엄청나게 가물가물.... 문제는 이 가물거리는 기억으로 인하여 오늘 개 쓴 맛을 봤다는 것이다.


일단...(자꾸 공부할꺼만 늘어나는 구나~^^) 운영체제의 메모리 관리 / 컴파일러의 메모리 관리 / 사용자의 메모리 관리 이 세 가지는 반드시 짚고 넘어가야 하겠다. 10, 11일 은 선거라서 쉰게 아니라 몸이 않좋았다능...ㅋㅋㅋ 


이번 주말에 수학 영어는 재껴도 이 부분은 반드시 공부를 하고 넘어가야 겠다.