본문 바로가기

메모리를 절약하는 방법

1. 가상 메모리만으로는 메모리 문제를 해결할 수 없다


GUI 기반인 윈도우는 그야말로 거대한 OS다.

MS-DOS의 초기 버전의 경우 128KB의 메모리만 있어도 충분했지만,

현재의 윈도우는 512MB은 되어야 쾌적하게 사용할 수 있다.

하지만 윈도우에 ⒞멀티태스킹 기능이 내장되면서 여러 개의 애플리케이션을 

동시에 실행할 수 있게 되었고, 이에 따라 512MB조차 모자란 경우가 많아졌다.


가상 메모리로 이 문제를 어느정도 해결할 수 있지만, 이는 보완책에 불과하다.

페이지 인과 페이지 아웃 작업이 시작되면, 디스크에 접근하게 된다. 

디스크는 메모리보다 접근 속도가 느리기 때문에, 이는 프로그램 실행 속도 저하를 야기한다.

이런 이유로 가상 메모리는 보완책일 뿐, 궁극적인 해결책이라고 할 수는 없는 것이다.


따라서 메모리 부족 문제를 해결하는 방법은 다음의 두 가지다.


① 실제 메모리의 용량을 늘린다.

② 애플리케이션의 크기를 줄인다.


①은 경제적 여유만 있으면 된다.

프로그래머라면 ②에 주목하자.


애플리케이션의 크기를 줄이는 방법은 크게 두 가지가 있다.


ⅰ. DLL 파일로 함수를 공유한다.


DLL(Dynamic Link Library) 파일은 프로그램이 실행될 때 ⒟라이브러리가 

동적으로(dynamically) 결합되어 있는 파일을 말한다.


여러 개의 애플리케이션이 같은 함수를 사용할 경우 그 함수를 DLL 파일로 만들어

애플리케이션들이 이 파일을 공유하도록 하면, 메모리 효율이 상승한다.



ⅱ. __stdcall로 함수를 호출한다. 


C언어는 함수를 호출할 때 그 함수의 ⒠스택 프레임이 만들어진다.

그리고 함수 실행이 끝나면 스택 프레임을 정리한다. 

이는 컴파일러가 자동적으로 스택을 정리하는 명령어를 추가함으로써 이루어진다.

이 때 기본적으로 함수를 호출하는 쪽(caller)에 추가된다.


그러나 이는 비효율적이다.

호출한 쪽에서 처리하는 경우 함수를 호출할 때마다 스택을 정리해야 하기 때문이다.

그러니까 함수를 호출할 때마다 스택 정리 명령어가 추가된다는 것이다.


__stdcall로 함수를 호출하면 호출한 쪽이 아니라 호출된 함수 쪽에서 스택을 정리하게 된다.

왜 호출된 쪽에서 스택을 정리하는 게 왜 메모리를 절약하는 방법일까?


이는 명령어 하나를 덜 수행하게 되기 때문에 실행 시간에서도, 메모리적 측면에서도 이득이다.

가변인자 함수에서는 사용할 수 없다는 단점이 있지만, 대부분 인자의 수가 정해져 있다.


함수의 실행이 끝날 때 공통적으로 해야하는 작업이 있다.

바로 스택 정리와 반환인데, 이를 어셈블리어로 보면 다음과 같다.


add esp, n

ret


여기서  add esp, n 은 스택 정리를 위해 추가된 명령어다. 

이는 ⒢__cdecl에서만 추가되는 명령어로, __stdcall의 경우 이 명령어를 추가하지 않는다.

다시 말해, 명령어 하나만큼 실행 시간과 프로그램 크기가 차이나는 것이다.


그런데 사실 이 차이점이 컴파일된 결과 코드에 미치는 영향은 별로 없다. 

스택 정리 주체와 상관없이 스택은 항상 호출 전의 상태로 복구되며 

프로그램의 동작도 완전히 동일하다. 

실행 속도는 거의 차이가 없고 프로그램의 크기는 무시할 만 한 수준이지만 __stdcall이 더 작다. 

왜냐하면 함수를 여러 번 호출하더라도 스택을 정리하는 코드는 함수 끝의 접미에 

딱 한 번만 작성되기 때문이다. 

반면 __cdecl은 호출원이 스택을 정리하므로 호출할 때마다 정리 코드가 반복되어 

프로그램 크기가 조금 더 커진다.




⒜GUI(Graphic User Interface): 컴퓨터 그래픽 기능을 사용하는 사용자 인터페이스


⒝MS-DOS(Microsoft Disk Operating System): MS(마이크로소프트) 사가 IBM 사로부터 의뢰받아 개발한 

                                                            IBM 컴퓨터용 운영체제.


⒞멀티태스킹(Multitasking): 여러 개의 작업을 동시에 수행하는 것.


⒟라이브러리(library): 함수, 클래스 등 컴퓨터 프로그램이 사용하는 비휘발성 자원의 모임.


⒠스택 프레임(stack frame): 함수 호출 시 매개변수, 함수의 지역변수, 함수의 복귀 주소 등이 저장되는 스택 영역.

  스택 프레임을 정리한다는 것은   add esp, 8  등의 명령어를 말한다.

  sub가 아니라 add인 것은 컴퓨터의 메모리에서 스택 영역은 

 높은 주소에서 낮은 주소로 쌓이기 때문이다.

 참고로 C언어에서 함수의 반환값은 레지스터를 통해 반환하게 되어 있다.


⒡__stdcall(STanDard CALL): ⒣함수 호출 규약 중 하나.  


⒢__cdecl(CDECLaration): 함수 호출 규약 중 하나.


⒣함수 호출 규약: 함수 호출 시 인자 전달 및 함수 종료 시 스택 정리에 대한 약속.

   크게 호출자 정리와 피호출자 정리로 나뉘며 전자에는 cdecl, 후자에는 stdcall, fastcall이 속한다.

'Programming > Basis' 카테고리의 다른 글

파일 압축  (0) 2019.03.18
디스크의 구조  (0) 2019.03.18
가상 메모리  (0) 2019.03.10
디스크 캐시  (0) 2019.03.10
프로그램이 실행되는 순서  (0) 2019.03.09