'윈도우즈'에 해당되는 글 4건

  1. 2011.04.25 윈도우즈 메모리 최적화의 구현 by movsd 2
  2. 2010.07.17 프로그램의 메모리 사용량 줄이기 by movsd
  3. 2008.03.07 로컬 웹서버를 이용한 웹광고 차단 by movsd 25
  4. 2007.12.03 공식 Windows PE by movsd 1

지난번의 메모리 사용 분석의 예에 이어, 이번에는 메모리 정리 유틸리티를 만들 수 있는 핵심 코드를 가지고 또다른 유틸리티를 하나 만들어 본다. 어렵게 생각할 것 없이 자기 취향이나 요구사항에 맞게 이 핵심코드를 포장하면 바로 완성이다.

원리

NT계통의 윈도우즈에서 사용되는 메모리 최적화 프로그램의 원리는 매우 단순하다. 즉, 현재 시스템에 돌아가고 있는 프로세스마다 SetProcessWorkingSetSize() 또는 EmptyWorkingSet()를 호출하는 것이다. 이 단순한 원리를 어떻게 사용자에게 제공하는가에 따라 CleanMem같은 모양을 가질 수도 있고, Minimem이나 Beautiful Memory같은 모양이 나오기도 한다.

위에서 한줄로 쓴 원리를 코드로 표현할 때에는, 현재 시스템에 돌아가고 있는 프로세스를 찾는 방식에 따라 몇가지 구현이 가능하다. 예를 들어, 윈도우즈 SDK에 포함된 예제중에 하나는 프로세스 목록을 얻기 위해 레지스트리를 읽어와서 그 내용을 해독한다. 다른 방법으로는 toolhelp32로 분류되는 API를 이용하는 방법이 있다. 이 방법을 이용해서 메모리 최적화 프로그램의 원리를 C 코드로 표현하면 다음과 같다.

HANDLE hProcess, hSnap;
PROCESSENTRY32 pe32;

hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (hSnap == INVALID_HANDLE_VALUE)
	return;

pe32.dwSize = sizeof(PROCESSENTRY32);
if (!Process32First(hSnap, &pe32)) {
	CloseHandle(hSnap);
	return;
}

do {
	hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE,
				pe32.th32ProcessID);
	if (hProcess) {
		EmptyWorkingSet(hProcess);
		CloseHandle(hProcess);
	}
} while (Process32Next(hSnap, &pe32));
CloseHandle(hSnap);
어떤 방식으로 루프를 구성하든지, OpenProcess()SetProcessWorkingSetSize() 또는 EmptyWorkingSet() 함수로 구성되는 루프내용은 동일하다.

요구사항

이미 있는 구현은 위에서 언급한 세가지 말고도 아주 많다. 아무리 그렇게 많아도 원리는 모두 똑같은 것이니 아무거나 자기 취향에 맞는 것을 골라서 사용하면 된다. 여기서 다시 만드는 이유는 다음과 같은 요구사항을 만족시키는 기존의 구현을 찾지 못했기 때문이다.

  • 간단한 원리를 실행하기 위해 배보다 배꼽이 더 커서는 안된다. 비주얼 베이직 런타임이나 .NET 프레임웍을 따로 설치하는건 딱 질색.
  • 실행 파일 자체가 뭔지 모를 도구로 압축되어 있는 것은 안된다. 이런 것은 도리어 메모리를 더 많이 소비하게 만들고 많은 경우에 보안사고로 연결된다. 바이러스 감시 프로그램이 압축된 실행파일을 경고하는 것은 다 이유가 있다.
  • 설정파일을 메모장으로 언제든지 읽어서 쉽게 설정을 바꿀 수 있어야 한다. 레지스트리 깊숙히 설정을 숨겨놓는 것은 설정할 때에도 곤란하고 나중에 삭제할 때에도 골치 아프다.
  • 한번 설치하면 일일이 신경쓰지 않고 잊어버려도 상관없어야 한다. 위의 작동 원리는 NT계통의 윈도우즈에서만 돌아가니까 NT 서비스로 돌아가면 좋겠다. 서비스로 돌아갈거면 자체적으로 사용하는 메모리 양도 적어야 한다.
  • 메모리 정리하지 않을 프로그램을 지정할 수 있어야 한다. 어떤 프로그램은 이미 자체적으로 메모리를 정리하고 있으므로 따로 해줄 필요가 없다. 불필요하게 건드리면 오히려 그 프로그램의 실행만 방해한다.
이런 요구사항은 주관적이고 개인적 취향일 뿐이지만, 이와 비슷한 요구사항에 맞는 메모리 관리 프로그램을 찾는다면 아래에서 다운로드 받을 수 있다.

설치

압축파일을 받아 적절한 곳에 압축을 풀면 다음과 같은 두개의 파일이 나온다.

wsmin.exe  (13312 바이트)  NT 서비스 실행파일
wsmin.ini  (3087 바이트)  간단한 설정파일

wsmin.exe는 NT서비스 실행파일이며 윈도우즈2000이상의 시스템에서만 작동한다. 설치를 완료하기 위해서는 NT서비스 데이타베이스에 등록해야 한다. 이는 명령행에서 다음과 같이 입력하면 된다. (관리자 권한이 필요하다.)

wsmin.exe /i
(이것이 귀찮거나 어렵다면 설치용 실행파일을 받아서 설치하는 수도 있다. 그런데, 설치용 실행파일로 설치하면 배보다 배꼽이 더 큰 느낌이 있다.)

설치가 완료되면 시스템 시동때마다 자동으로 시작하게 기본값이 설정되어 있다. 이것을 바꾸려면 시작-제어판-관리도구-서비스를 열어서 Working Set Minimizer라고 된 것을 찾아 바꾸어주면 된다. (고수들은 명령행에서 services.msc라고 치는 것을 좋아한다.)

Working Set Minimizer 서비스가 등록된 상태

설정

설정파일은 wsmin.ini이며, 없어도 상관없다. 설정파일이 없으면 밑에서 설명하는 기본값들을 가지고 서비스가 작동한다. 만일 설정파일이 있다면 실행파일과 같은 디렉토리에 있어야 한다. 설정을 바꾸는 방법은 메모장(notepad.exe)같은 편집기로 열어서 이하에서 설명하는 항목을 편집하고 저장하면 된다. 변경한 설정을 적용하기 위해서는 wsmin.exe를 다시 시작한다. 이를 위해서는 시작-제어판-관리도구-서비스를 열어서 Working Set Minimizer라고 된 것을 찾아 "다시 시작"을 누르면 된다.

설정할 수 있는 것들 중 중요한 것은 메모리 정리하는 시간 간격과 정리하지 않을 파일들의 목록이다. 그외에도 심각한 오류를 기록할 로그파일 이름과 부팅이 느린 시스템에서 처음 메모리 정리까지 기다릴 시간을 설정할 수 있다.

메모리를 정리하는 시간간격은 1분부터 480분(= 8시간)사이의 값을 분 단위로 적어준다. 기본값은 30분이다.

[Settings]
Interval=60
이 예에서는 60분(=1시간)마다 한번씩 메모리 정리를 하게 지정했다.

그런데 이 프로그램은 시스템이 시작할때 자동으로 실행하는 것을 상정하고 있기 때문에, 프로그램 실행 이후 최초로 메모리 정리 작업을 하기까지 일정시간을 기다린다. 이는 부팅이 느린 시스템에서 다른 서비스들과 드라이버들을 올리기 전에 섣불리 메모리 정리를 시도하다가 시스템을 불안정하게 만드는 것을 방지하기 위해서 정한 값이다. 이 값도 역시 1분부터 480분 사이의 값을 분 단위로 설정할 수 있으며, 기본값은 1분이다.

[Settings]
InitialWait=3
이 예에서는 맨 처음으로 메모리를 정리하기까지 3분을 기다리게 설정했다. 하지만 오래된 시스템에서 안티바이러스를 여러개 실행하고 키보드 보안 프로그램을 겹겹이 띄우는 시스템이 아니면 보통 기본값으로도 충분하다.

메모리 정리에서 제외할 실행파일 이름은 [Ignore]섹션에 한줄에 하나씩 적어준다. 예를 들어, 서비스 관리자에는 손대지 않으려면

[Ignore]
services.exe
이렇게 설정하면 된다. 그런데, 어떤 경우에는 전혀 다른 프로그램이 같은 실행파일 이름을 가지는 경우가 있다. 이때 그중 일부만 working set을 정리하고 나머지는 손대지 않도록 하려면, 제외할 실행파일의 경로명 전체를 써준다.
[Ignore]
C:\WINDOWS\system32\services.exe
실행파일 경로에서 공백문자는 모두 유의미하다고 인식한다.

삭제

이 프로그램을 삭제하려면, 우선 서비스를 종료하고 명령행에서 다음과 같이 입력하여 서비스 데이타베이스에서 삭제한다.

wsmin.exe /u
그 다음에 실행파일을 지우고 설정파일이나 로그파일도 지우면 삭제가 완료된다. (설치용 실행파일로 설치했다면 제어판을 통해서 삭제하면 된다.)

덧붙임

이미 언급한 바와 같이, working set을 줄이는 메모리 최적화는 메모리 할당/해제를 제대로 하지 않는 그저 그런 품질의 프로그램을 많이 실행할 때에 큰 효과가 있다. 그런 프로그램은 아예 사용하지 않는다면, 그 어떤 메모리 최적화 프로그램도 소용이 없다. 이런 경우에는 메모리 최적화 프로그램을 사용하는 만큼 메모리를 손해보는 것 밖에 없다.

게임은 메모리 정리 프로그램을 써봤자 소용없는 경우다. 가만 생각해보면 게임의 실행속도를 높이기 위해 굉장히 큰 캐쉬를 사용하는게 너무나 당연해서, 그 틈에 메모리 낭비가 있을 법도 하다. 그런데도 메모리 정리가 소용없는 이유는 게임을 실행하는 중이라면 그 게임이 실질적으로 유일한 작업이나 다름없기 때문이다. 바꾸어 말하면, 게임을 하는 중이라면 워드프로세서, 웹브라우저, 기타 등등 여러개의 작업이 게임과 함께 동시에 돌아갈 가능성이 별로 없다. 이런 상황에서는 메모리 정리를 해봐야 게임만 느려지고 다른 프로그램을 위해 메모리를 확보하는 효과도 없다.

파일

다운로드 전에: 이 프로그램을 실행함으로써 발생할지도 모르는 어떠한 불상사에 대해서도 제작자는 책임지지 않는다. (이는 더도 아니고 덜도 아니고 딱 마이크로소프트 수준의 사용허가 문구이다.)

wsmin.zip은 아래 표에 적힌 파일들이 담긴 압축파일이다. 압축을 풀고 NT서비스 데이타베이스에 등록해야 설치가 완료되며, 이에 관해서는 위의 설명을 참조하면 된다. 이런 작업이 귀찮거나 어려운 사람들은 wsminsetup.exe를 받아서 실행하면 설치가 된다. 이것은 똑같은 내용물을 Inno Setup을 이용하여 설치파일로 만든 것이다.

단순 압축 파일:   설치 실행 파일:
wsmin.zip의 내용물
wsmin.exe  (13312 바이트)  NT 서비스 실행파일
wsmin.ini  (3087 바이트)  간단한 설정파일
Posted by movsd
,
메모리 정리 프로그램 자체를 검색하다가 찾아온 것이라면 다음에 이어지는 포스팅에 C로 표현한 핵심코드, 기존 프로그램 몇개에 대한 링크와 개인적 요구사항에 맞추어 새로 하나 만든 것이 있고, 이 포스팅은 working set자체를 어떻게 해석하는가에 중점이 맞추어져 있다는 것을 미리 밝혀둔다.

윈도우즈의 메모리를 관리/정리/최적화해준다는 프로그램들을 많이 보았을 것이다. 이런 프로그램들은 항상 그 유효성에 관해 논란이 있기 마련이다. 최근에 웹광고를 비켜가는 방법으로 사용하는 가짜 웹서버메모리 사용량을 줄였으면 좋겠다는 개선점 제안을 받고, 이것을 구현하는 과정에서 한동안 잊어버리고 있던 부분을 다시 찾아보고 정리해 볼 기회가 되었다.

메모리 정리 방법

메모리 정리 프로그램은 윈도우즈95가 시장을 지배하던 시절에도 있었다. 당시에 사용되던 방법은 RAM의 용량만큼 메모리 할당을 시도하는 것이었다. 메모리 정리와 전혀 관계없이 보이는 이 작업이 효과가 있는 듯이 보인 이유는 단 하나이다. 운영체제가 메모리 할당 요청에 응하면서 당장 쓰이지 않는 부분을 swap파일로 옮겨버린다. 그 결과로 이 프로그램이 메모리를 모두 돌려주고 종료하면, RAM이 텅 비어버린다. 이 원리를 이해하고 나면, 이 방식은 실제로 메모리를 정리하지 않는다는 것을 금방 알게된다. 자연스럽게 사기논란이 일어났고, 요즘은 초보 프로그래머가 아니면 이 방식을 쓰지 않는다.

다른 방식은 NT계통의 윈도우즈가 시장을 지배하면서 나타난 것으로, 윈도우즈가 내부적으로 사용하는 방법을 이용하는 것이다. 작업관리자로 메모리 사용량을 지켜보다 보면, 어떤 프로그램을 최소화하면 메모리 사용량이 확 줄어버리는 것을 본 적이 있을 것이다. 그것을 모든 프로그램에 적용하자는 것이 요즘 메모리 정리 프로그램의 기본 아이디어이다. 이는 윈도우즈 API로 제공되는 SetProcessWorkingSetSize()EmptyWorkingSet() 함수를 사용한다. 이 방법은 brhttpd를 개선하는데 사용된 방법이기도 하다.

자신의 프로그램의 메모리 사용량을 줄이기 위해서 이 방법을 사용하고자 한다면, 적절한 위치에

SetProcessWorkingSetSize(GetCurrentProcess(), -1, -1);
이렇게 한줄 집어 넣음으로써, 지금까지 사용하던 메모리중 당장 쓰는 것을 빼고는 다 털어버리게 한다. 그 다음에는 page fault 메카니즘을 통해 다시 필요한 부분을 메모리에 올린다. 당연한 얘기이지만, page fault는 프로그램의 실행속도에 영향을 주게 된다. 그럼에도 불구하고 .net환경에서 개발하는 사람에게는 메모리 사용량을 줄이는 방편으로 이 방법이 권장되기도 한다.

문제의 핵심: working set

윈도우즈 API를 사용해서 메모리를 정리한다고 해도 논란이 잦아들지는 않았다. 논란이 아직도 계속되고 있다는 것을 웅변하듯이, 메모리 정리 프로그램 중의 하나인 CleanMem은 홈페이지의 아래 절반을 자기 프로그램이 효과가 있다고 주장하는 것에 할애하고 있다. 이 프로그램은 프로세스마다 EmptyWorkingSet() 함수를 호출하는 매우 단순한 비주얼베이직 프로그램이다. 그러므로 윈도우즈가 효과가 있는 만큼 이 프로그램이 효과가 있다는 주장이 나름대로 설득력이 있다. 그러나, 이 프로그램이 효과가 없다는 주장도 마찬가지로 설득력이 있다. 그 이유는 working set에 대한 해석에 달려있다.

Working set은 MSDN페이지에 잘 설명되어 있듯이 현재 물리적 메모리(RAM)에 상주하고 있는 가상 메모리 부분이다. 작업관리자가 보여주는 메모리 사용량은 바로 이 working set의 양이다. Working set은 다시 공유 가능한 부분과 공유 불가능한 부분으로 나누어진다. 보통, 공유가 불가능한 부분은 현재 프로세스의 데이타이고, 공유가 가능한 부분은 DLL이나 프로세스간 통신을 위한 공유메모리 같이 말그대로 공유하도록 만들어진 부분이다. 공유가 가능한 부분의 대부분은 실제로 공유된다.

Working set의 구분을 보면 바로 떠오르는 의문은, 공유하고 있는 부분을 각각의 프로세스의 메모리 사용량으로 계산하는 것이 정확한 것인가 하는 질문이다. 예를 들어, kernel32.dll같이 모든 사용자 모드 프로그램이 공유할 수 밖에 없는 DLL은 프로세스의 갯수만큼 RAM을 사용하고 있다고 계산되는데, 실제로 점유하고 있는 RAM의 양은 DLL하나에만 해당한다. (그렇지 않다면 DLL이 아니다!) 프로세스가 오로지 하나만 돌아가고 있다면 이 계산은 맞지만, 그렇지 않다면 작업관리자가 보여주는 메모리 사용량은 과다계상되고 있는 것이다.

두번째로 생기는 의문은, working set을 다 비우고 처음부터 다시 구성한다면 과연 효율적으로 메모리 사용량을 재편할 수 있는가 하는 질문이다. 아까의 예를 계속하면, kernel32.dll은 어차피 메모리에 상주하고 있을 것이다. 그렇다면 프로세스 하나의 working set을 비우고 다시 (soft) page fault를 거쳐 kernel32.dll의 필요한 부분만 이 프로세스의 working set에 포함한다면, 메모리 사용량이 줄어들었다고 볼 수 있는가 하는 의문을 가지게 된다.

사례 분석

불행한 일이지만, 정답은 없다. 정답이 있었다면 애초에 논란이 생기지도 않았다. 결국 사용자로서 할 수 있는 일은, 자신이 주로 사용하는 프로그램들이 메모리 정리 프로그램의 효과를 볼 수 있는지 알아보고 결정하는 수 밖에 없다. 개발자라면 자신의 (메모리 누수가 없는) 프로그램의 working set을 분석해보고 SetProcessWorkingSetSize() 함수를 쓸 것인지 결정할 수 있다.

간단한 working set 분석의 예로 VMMap을 이용하여 brhttpd에서 메모리 정리 이전과 이후를 비교해보자. 이를 위해서 brhttpd의 자체 메모리 정리 기능은 사용하지 않도록 설정하고 실행한다.

[Settings]
MemCleanTimeOut=-1
이제 VMMap을 실행하여 brhttpd.exe를 선택하면 다음과 같은 화면이 보인다. 메모리 정리 이전의 VMMap 실행화면 이 화면은 메모리 정리 이전의 사용량을 보여준다. 화면에서 보이듯이 시스템 DLL이 차지하는 양이 꽤 많다. 이제 메모리 정리 프로그램이 하듯이 working set을 비운다. 메뉴에서 Empty Working Set을 선택하거나 Ctrl-E를 누른다. 그리고 나서 새롭게 재편된 메모리 사용량을 보기 위해 Refresh를 선택한다. 메뉴에서 Refresh를 선택하거나 F5를 누른다. 메모리 정리 이후의 사용량은 다음과 같은 화면으로 나타난다. 메모리 정리 이후의 VMMap 실행화면

그림에 나와있는 숫자만 읽어보면 전체 working set이 1680KB에서 188KB로 줄어들었으니 90%에 가까운 효율을 보이는 메모리 절약의 효과가 있다고 볼 수도 있다. 이것을 좀더 자세히 들여다 보기 위해, 메모리 사용량이 차이를 계산해보면 다음의 표와 같다.

EmptyWorkingSet() 함수로 절약한 메모리 양 (단위: KB)
TypeTotal WSPrivate WSShareable WSShared WS
Total-1,492-212-1,280-1,268
Image-1,260-104-1,156-1,144
Mapped File-480-48-48
Shareable-760-76-76
Stack-20-2000
Private Data-88-8800

이 표를 보면 메모리 절약의 효과의 대부분이 공유가능한 working set부분에서 나타났음을 볼 수 있다. 실제로 공유된 부분이 절감된 수치(오른쪽 마지막 열)를 보면 공유 가능한 부분은 실제 공유가 이루어지고 있었다. (12KB의 차이는 brhttpd가 한번만 실행되었기 때문에 그 실행파일 이미지는 공유할 기회가 없어서 생긴 것이다.)

공유가 되고 있었던 부분중에 절약된 부분을 알아보기 위해 VMMap의 아래쪽 창을 보면, 공유가 되고 있었던 Image 영역은 대부분 시스템 DLL이다. 여기서 절약된 1MB 남짓한 부분중에, brhttpd.exe 실행파일에 20KB를 할당했던 것을 필요한 부분 8KB만 남기고 털어버리는 12KB의 절약분을 제외하면, 실제로 RAM에서 없어졌을 것 같이 보이지 않는다. 다시 말하면, brhttpd가 쓰는 부분만 골라서 사용량을 계산했을뿐이지, 실제로 RAM에서 시스템 DLL을 내려서 메모리를 정리했을 가능성이 없다는 것이다. Mapped file이나 shareable 영역도 비슷한 얘기가 이어진다.

이렇게 생각해보면 working set을 비워서 얻게되는 실질적인 절약효과는 공유가 불가능한 working set에서 생긴다는 것을 알 수 있다. 이미 설명한 바와 같이 공유가 불가능한 working set은 프로그램의 데이타이다. 위의 표에서는 image영역, 스택 영역, 그리고 프로그램 데이타 영역에서 메모리 절약이 있다.

위의 예에서 image영역의 비공유 working set의 대부분이 사라진 것은 메모리 정리의 효과가 빛을 발하는 부분이다. 둘째로, 스택영역은 운영체제가 관리하는 부분이므로, 운영체제가 약간 여유를 준 부분을 빡빡하게 만드는 효과가 있다. 하지만, 원래 운영체제에서 메모리를 방만하게 관리하지 않으므로, 절약되는 바이트 수는 미미할 수 밖에 없다. 마지막으로, 순수한 프로그램 데이타에서 절약되는 부분은 working set을 비우는 것의 효과가 제일 중요한 부분이다. (여기에도 환경변수영역같이 운영체제가 생성하는 부분이 포함되기는 하지만, 그 크기는 상대적으로 작다.) 이 부분에는 프로그램을 짤때 메모리의 재사용을 미리 고려할 수 없어서 생기는 (어쩔 수 없는) 낭비도 포함된다. 사용자의 입장에서는 이 부분이 절약되는 것이 가장 기분 좋은 일이다.

brhttpd의 경우, 비공유 working set이 200KB정도 절약되는 것은, 정리 이전에 350KB남짓한 비공유 working set을 사용하고 있었다는 것에 비추어 보면 엄청난 양의 절약이라고 판단된다. 이 판단에 기초하여 working set을 줄일 수 있는 선택이 가능하도록 개선하였다. 그러나, 실제로 절약되는 부분이 200KB 정도에 불과하다면, 몇 GB짜리 RAM의 0.1%도 안되는 미미한 양이라고 생각할 수도 있다. 한편, 절약되는 200KB의 대부분은 빈 페이지를 보여주는 작업을 할 때에 다시 사용된다. 그래서, 메모리 정리에 관한 부분을 아예 신경쓰지 않도록 설정할 수도 있게 지원한다.

아직도 남은 논란

사용자의 입장에서 안 쓰는 프로그램 데이타 영역을 절약하는 것은 기분 좋은 일이라고 이미 말한바 있다. 그런데, 개발자라면 프로그램 데이타가 차지하는 working set이 많이 감소한다는 것을 다른 관점에서 봐야한다.

순수 프로그램 데이타가 상당히 크게 늘어나면서 당장 필요하지 않은 부분이 아주 많다면, 그것은 어디인가 메모리 누수가 있기 때문일 가능성이 매우 높다. 그렇지 않다면, 자체 캐쉬 알고리즘을 사용하고 있는데, 그 구현에 뭔가 헛점이 있다는 말이다. 그렇다면, 지금 당장은 임시방편으로 SetProcessWorkingSetSize() 함수를 이용해 메모리를 정리하더라도, 언젠가는 코드를 꼼꼼히 점검해봐야 하는 상황인 것이다.

한편, 이런 개발자의 관점은 사용자에게 새로운 시각을 제공한다. 프로그램 데이타 관리를 허술하게 해서 메모리 정리 프로그램을 따로 쓰게끔 만드는 응용프로그램을 쓸 것인가, 아니면 꼼꼼하게 짜여진 응용프로그램을 쓰고 메모리 정리 프로그램 같은 것은 잊어버릴 것인가 하는 질문을 해보는 것이 그것이다. 꼼꼼하게 짠 응용프로그램만 쓴다면 메모리 정리 프로그램을 써봐야 별 효과가 없을 것이고, 그렇게 되면 또다시 논란에 불을 지피는 묘한 피드백이 생긴다.

Posted by movsd
,

해결하고자 하는 문제

많은 사람들이 이제는 hosts파일을 편집하여 광고를 거부하는 방법을 알고 있다. 그 방법의 문제점은, 자기 컴퓨터에 웹서버가 설치되어 있지 않는한, 매우 보기 싫은 "연결실패"화면이 섞여 나온다는 것이다.

그 와중에, 뒤로가기 버튼이 말을 안듣는 짜증스러움도 수반된다. 사실은 뒤로가기가 망가진 것이 아니라, 브라우저의 연결실패 처리가 깔끔하지 못해서, 뒤로가기 목록에 따로따로 쌓여서 그런일이 벌어진다. 이유야 어쨌건, 사용하는데 불편하기는 매한가지이다.

기존의 해결방법

이러한 문제를 해결하는 프로그램으로 센스부족이라는 것이 있다. 일단 그 크기가 작아서 좋다. 또, 이 프로그램은 기피대상이 되는 사이트의 블랙리스트를 따로 관리하면서 필요에 따라 hosts파일을 편집하는 편의도 제공한다. 요컨대, 넷웍 초보의 편의를 고려한 유용한 프로그램이라고 한마디로 요약할 수 있다.

그런데, 한글지원을 추가하지 않은 윈도우즈에 "센스부족"을 설치했다가 메뉴를 볼 수가 없어서 매우 당황했다. 이것은 리소스만 약간 손봐주면 쉽게 해결될 수 있다. 한편, 어떤 이유에서인지 "센스부족" 서버는 PMS_SERVER라는 보이지 않는 윈도우를 생성한다. 보통 NT서비스는 윈도우를 생성하지 않기때문에, 처음으로 이 윈도우를 발견했을 때에는 스파이웨어가 들어온 것으로 착각하고 한참 법석을 떨었다.

이런 점들을 조금만 고쳐 사용했으면 좋겠는데, 애석하게도 "센스부족"은 소스가 제공되지 않아서, 처음부터 다시 만들어야 했다.

원리와 단순한 구현

해결책의 원리는 이미 "센스부족"의 제작자가 잘 설명을 해 놓았다.

[...] 로컬에 작고 가벼운 가짜 웹서버가 서비스 형태로 설치되며, 이 웹서버는 무조건 빈페이지를 보여주는 역할을 한다. [...]

우선, "가짜 웹서버"라는 것은 80번 포트를 열어놓고 기다리고 있는 넷웍 통신 프로그램이라는 애기이니, 넷웍 프로그래밍에 관한 책을 조금 읽어보았으면 당장 socket(), bind(), listen()으로 이어지는 상용구와 select()/accept()의 무한루프를 떠올렸을 것이다. 여기서 "가짜"라는 표현대로, 제대로된 웹서버를 구현하는 것이 아니니, 어렵게 생각할 필요가 없다.

그 다음 "서비스 형태로 설치"된다는 것은, NT 서비스를 작성하는 요령에 따라 프로그램을 짜면 된다는 얘기이다. 이는 윈도우즈 SDK에 간단한 예가 있는 것을 비롯해, MSDN에 설명이 잘 되어 있으니, 더이상의 설명이 필요 없다.

마지막으로 "무조건 빈페이지를 보여주는" 응답의 가장 간단한 형태를 C로 표현하면 다음과 같다.

/*
 * int fd에는 accept()로부터 얻은 소켓이 있다.
 * char buf[]에는 브라우저로부터의 HTTP요청이 있다.
 * 이 요청이 유효한 것임은 여기 오기전에 확인한다.
 */
if (memcmp(buf, "GET ", 4) == 0) {
    send(fd, "HTTP/1.1 200 OK\r\n"
"Server: server name\r\n"
"Connection: close\r\n"
"Content-Type: text/html\r\n\r\n", len, 0);
    shutdown(fd, SD_SEND);
}
else {
    /* 501 오류를 보내거나 다른 응답을 한다. */
}
close(fd);
물론, 이 프로그램은 윈도우즈 소켓을 사용할 것이므로, fdSOCKET형이고, close()closesocket()을 써야한다는 것만 유념하면 된다. GET요청이 아닌 다른 요청들에 대해서는, 구현하지 않았다는 의미의 501 오류를 보내거나 적절히 구현해서 응답을 하면, 목표하던 기능구현을 완성하게된다.

이렇게 해석을 해놓고 나면, 구현자체는 넷웍 프로그래밍 입문자를 위한 연습문제 수준에 불과하다는 것을 쉽게 알 수 있다. 이 연습문제 풀이에 약간의 살을 덧붙인 것은 밑에서 받을 수 있다.

단순한 구현의 사용법

설치: 압축파일을 받아서 적당한 곳에 압축을 풀면 두개의 파일이 나온다. 실행파일은 윈도우즈2000 이상의 시스템에서만 정상적으로 작동한다.

brhttpd.exe  NT 서비스 실행파일
brhttpd.ini  간단한 설정파일

설치를 완료하기 위해서는 NT서비스 데이타베이스에 등록해야 한다. 이는 명령행에서 다음과 같이 입력하면 된다. (관리자 권한이 필요하다.)

brhttpd.exe /i
이것으로 가짜 웹서버가 설치가 완료되고 돌아가게 된다. 기본설정은 시스템 시동때마다 자동으로 시작하게 되어있다. 이를 바꾸려면, 시작-제어판-관리도구-서비스를 열어서 Local-only HTTP Server라고 된 것을 찾아 바꿔주면 된다. (고수들은 services.msc라고 명령행에 치는 것을 즐겨쓴다.)

설정: brhttpd.ini는 간단한 설정파일이다. 설정파일은 실행파일과 같은 디렉토리에 있어야 한다.

여기서 설정할 수 있는 것은 로그파일 이름과 열어둘 포트 목록, 그리고 메모리 사용량 최소화를 위한 시간간격이다. 설정파일은 없어도 상관없다. 설정파일이 없으면, 로그파일은 실행파일이 있는 디렉토리에 brhttpd.log라는 이름으로 생기며, 가짜 웹서버는 80번 포트를 열어놓고 기다린다. 기다리는 시간이 1분이 넘어가면 가짜 웹서버는 사용메모리를 최소화하고 계속 기다린다.

설정은 서비스가 시작할 때마다 읽어들인다. 설정을 변경한 후에 이를 적용하려면, 시작-제어판-관리도구-서비스를 열어서 Local-only HTTP Server를 재시작하면 된다.

로그파일 이름은 가급적이면 드라이브이름까지 포함하여 지정하는 것이 나중에 로그파일 찾기에 도움이 된다. 상대경로로 지정하면 윈도우즈는 %systemroot%\system32의 상대경로로 해석한다. 로그파일 생성 자체를 막으려면 로그파일 이름을 NUL이라고 주면 된다.

[Settings]
LogFile=NUL

포트는 최대 64개까지 지정할 수 있다. 상식적으로 생각할때, 64개는 지나치게 많지만, 가끔은 상식이 설명하지 못하는 일들이 벌어지기도 한다. 포트를 지정하는 키는 port0에서 port63까지이며, 순서대로 쓸 필요도 없고, 키번호가 건너뛰어도 상관없다.

[Settings]
port0=80
port10=8080
이 예에서는 80번 포트와 8080번 포트를 열어놓도록 지정했다.

버전 1.1에 새로 추가된 설정: 웹서핑을 하지 않을 때에는 가짜 웹서버도 메모리를 덜 사용하도록 지정할 수 있다. 가짜 웹서버가 웹서핑이 없다고 판단하는 기준은 가짜 웹서버에 HTTP요청이 들어오는 시간간격이다. 일정 시간동안 HTTP요청이 들어오지 않으면, 가짜 웹서버도 할 일이 없다고 판단하고 메모리 사용량을 최소로 줄이게 한다. 사용자가 설정하는 것은 바로 그 시간간격을 초 단위로 적어주는 것이다. 이 값이 설정되지 않으면 기본값으로 1분을 설정한다.

[Settings]
MemCleanTimeOut=120
이 예에서는 2분동안 가짜 웹서버로 HTTP요청이 들어오지 않으면 메모리 사용을 최소화하도록 지정했다. 시간간격의 최대값은 1시간(=3600초)이며, -1을 지정하면 메모리 사용량을 줄이려는 시도를 하지 않는다. 메모리 사용량을 줄이는 기법은 CleanMem이나 그 비슷한 프로그램들과 같은 기법을 사용한다. 그런 프로그램과 기법이 유효한지는 논란이 아직 많다. 이 기법에 회의적이라면 -1로 설정하면 된다.
[Settings]
MemCleanTimeOut=-1
시간간격이 너무 길면 메모리 절약효과가 없고, 너무 짧으면 메모리 절약은 되더라도 다른 측면에서 비효율이 발생한다. 어림값으로는 한 웹페이지에 평균적으로 머무는 시간을 정하면 된다.

삭제: 프로그램을 삭제하려면 우선 서비스를 종료하고

brhttpd.exe /u
라고 명령행에 입력하여, 서비스 데이타베이스에서 삭제한다. (관리자 권한이 필요하다.) 그후에는 실행파일을 지우고, 설정파일이나 로그파일이 있으면 지우면 된다.

한계

가짜 웹서버를 사용하는 것은, 근본적으로 hosts파일을 사용하여 광고서버로 가는 트래픽을 다른 곳으로 돌리는 방법에 추가적인 편의를 덧붙인 것 뿐이다. 따라서, hosts파일 편집방법의 한계를 고스란히 안고 있다. 예컨대, 광고서버가 따로 분리되어 있지 않고, 광고와 정상적인 내용이 같은 도메인 네임을 가진 서버에서 제공된다면, 이 방법은 전혀 효과가 없다.

이를 해결하려면 브라우저마다 확장으로 제공되는 프로그램을 사용하거나, 파이어폭스에서는 userContent.css를 직접 편집하는 방법을 쓸 수 있다. 한편, 여기의 방법을 좀더 발전시켜, 프록시 서버로 확장하여 HTTP요청을 일일이 걸러내는 방법도 가능하다.

파일

다운로드 전에: 이 프로그램을 실행함으로써 발생할지도 모르는 어떠한 불상사에 대해서도 제작자는 책임지지 않는다. (이는 더도 아니고 덜도 아니고 딱 마이크로소프트 수준의 사용허가 문구이다.)

버전: 1.2 (2014년 7월 21일)
달라진 점: 내부 구조를 바꾸고 몇가지 사소한 버그를 고쳤다. (사용자가 바로 느낄만한 기능상의 차이는 없다. 그러므로 이전 버전을 사용하면서 문제가 없었다면 굳이 업데이트할 필요는 없다.) 64 비트용 실행파일이 추가되었다. 컴퓨터에 설치된 윈도우즈에 따라 32비트용과 64비트용 실행파일을 자동으로 선택해서 설치한다.

brhttpd-1.2.exe
brhttpd.exe  (32비트용: 11776 바이트)  NT 서비스 실행파일
   (64비트용: 14848 바이트)   
brhttpd.ini  (2475 바이트)  간단한 설정파일

사용 예

(2010년 3월 12일 추가)

Posted by movsd
,

공식 Windows PE

miscellaneous 2007. 12. 3. 14:21

윈도우즈 쓰는 사람중에 생초보가 아닌 이상 BartPE가 무엇인지 한번쯤은 들어봤을 것이고 써봤을 것이다. 마이크로소프트에서 Windows PE를 제공하기는 하지만, 그것은 오로지 볼륨라이선스 구매자들에게만 제공되어서, 개인사용자는 애시당초 구경조차 할 수 없었다. 그 유용성을 개인사용자들도 누릴 수 있게 도와주는 것이 바로 BartPE였다.

그런데, BartPE가 유용하기는 하지만, 항상 찜찜한 것은 BartPE가 말그대로 "흉악한" hack이라는 것이었다. 마이크로소프트에서 제작방법을 설명한 공식적인 문서가 있는 것도 아니고, 그렇다고 해서 마이크로소프트가 문서는 줄 수 없지만 이렇게 써도 된다라고 공식적으로 인정한 것도 아니고, 이래저래 돌아가기는 하는데 언제 망가질지 모르는 불안감을 안고 쓰는 프랑켄슈타인의 괴물이었다.

지난 2월에 마이크로소프트에서 공식적으로 누구나 쓸 수 있는 Windows PE를 발표했다. 다운로드 할 파일은 영문판한글판이 따로 있다. 관련 문서는 영문으로만 제공된다.

(추가: Windows 7용 AIK도 영문판한글판이 따로 있다.)

공식적으로 (그리고 무료로) 비상복구용 PE를 사용하게 해주는 점은 마이크로소프트에 고맙게 생각하지만, 새 제품 판매를 위해서인지 윈도우즈 비스타를 요구하는 것은 마음에 들지 않는다. 게다가, 무료로 배포하면서 왜 그리 다운로드 링크를 꼭꼭 숨겨놓았는지는 알 수 없다. (나도 아홉달이나 지나서야 그 존재를 알았으니...) 이런 정도로 사용자를 지원하는 정성이면, 오히려 나서서 광고를 크게 할 만도 한데.

Posted by movsd
,