난이도 : 초급
Emma Shepherd, 소프트웨어 엔지니어, IBM UK Labs
Martin Trotter, 소프트웨어 엔지니어, IBM UK Labs
Caroline Maynard, 소프트웨어 엔지니어, IBM UK Labs
Matthew Peters, 소프트웨어 엔지니어, IBM UK Labs
2004 년 11 월 16 일
자 바 런타임이 대규모의 메모리 관리를 핸들하더라도 프로그램의 메모리 사용에 대해 관심을 기울이면 머신 퍼포먼스를 최적화하고 메모리 유출을 감지하는데 큰 도움이 된다. Windows에서 메모리 사용을 감시하는데 사용할 수 있는 많은 툴이 있다. 사용 관점에 따라 장단점을 갖고 있다. 필자는 메모리 사용에 대한 몇 가지 잘못된 개념들을 바로잡고 툴 사용법을 설명하겠다.
자바의 잘 알려진 장점들 중 하나는, C 프로그래머와는 달리, 자바 프로그래머가 필요한 메모리를 할당하고 비우는 등의 성가신 책임을 질 필요가 없다는 점이다. 자바 런타임이 이 일을 관리하기 때문이다. 메모리는 각 인스턴스화된 객체를 위한 힙 영역에 자동으로 할당되고 가비지 컬렉터는 더 이상 필요하지 않는 객체로 채워진 메모리를 주기적으로 비운다. 하지만 그렇다고 해서 완전히 의무에서 벗어난 것은 아니다. 프로그램의 메모리 사용을 감시해야 하는데, 그 이유는 자바 프로세스의 메모리는 힙에서 부유하는 객체 이상의 것들로 구성되기 때문이다. 이것은 또한 프로그램용 바이트코드(런타임 시 JVM이 변환하는 명령어), JIT 코드(목표 프로세서를 위해 이미 컴파일된 코드), 원시 코드, JVM이 사용하는 메타데이터(테이블, 라인 넘버 테이블 등 제외) 등으로 구성되어 있다. 원시 라이브러리 같은 특정 유형의 메모리는 프로세스 간 공유될 수 있기 때문에 자바 애플리케이션의 실제 풋프린트를 결정하는 일이 어려워질 수 있다.
Windows에서 메모리 사용을 감시할 툴들은 많이 있지만 안타까운 것은 이중 어떤 것도 우리가 필요로 하는 정보를 주는 것은 없다. 게다가 다양한 툴들 자체도 공통의 어휘를 공유하지 않는다. 이 글에서 무료로 사용할 수 있는 유용한 툴들을 소개하고 사용 방법을 설명하겠다.
이 글에서 설명할 툴을 이해하기에 앞서 Windows가 메모리를 관리하는 방법을 이해해야 한다. Windows는 demand-paged virtual memory 시스템을 사용한다.
가 상 메모리 개념은 실제 메모리에 한번에 맞지 않는 프로그램을 다루는 복잡한 문제에 대한 솔루션으로서 1950년대에 생겨났다. 가상 메모리 시스템에서 프로그램들은 물리적으로 사용할 수 있는 것보다 큰 주소 세트에 접근할 수 있고 메모리 매니저가 이들 논리적 주소들을 실제 위치로 매핑하면서 디스크상의 임시 스토리지에 오버플로우를 저장한다.
Windows가 사용하는 가상 메모리 구현에서 가상 스토리지는 페이지(page)라고 하는 동일한 크기의 단위로 구성된다. 각 운영 시스템 프로세스는 각자의 가상 주소 공간을 할당 받는다. 이 가상 메모리 페이지들은 읽기와 쓰기가 가능하다. 각 페이지는 세 가지 상태 중 하나가 될 수 있다:
그림 1은 프로세스의 주소 공간에 있는 가상 페이지들이 메모리의 물리적 페이지 프레임으로 매핑되는 방법을 보여주고 있다.
32 비트 머신(주로, Intel 프로세서)에서 구동하고 있다면 프로세스를 위한 전체 가상 주소 공간은 4GB이다. 4GB는 32 비트로 처리할 수 있는 가장 큰 용량이기 때문이다. Windows에서는 여러분이 주소 공간의 모든 메모리에 접근할 수 없다; 프로세스는 개인적으로 사용할 때 반 이하를 갖게 되고 Windows는 그 나머지를 사용한다. 2GB 개인 영역에는 프로그램을 실행하기위해 JVM이 필요로 하는 대부분의 메모리가 포함되어 있다: 자바 힙, JVM을 위한 C 힙, 프로그램 쓰레드용 스택, 바이트코드와 JIT 메소드를 보유하기 위한 메모리, 원시 메소드가 할당하는 메모리 등.
크고 인접한 영역의 메모리를 할당하기는 하지만 이 모든 것을 즉시 필요로 하지 않는 프로그램들은 Reserved와 Committed 메모리의 조합을 사용한다. JVM은 자바 힙을 이러한 방식으로 할당한다. JVM의 -mx
매개변수는 힙의 최대 사이즈에 대해 지시하지만 JVM은 시작할 때 모든 메모리를 할당하지는 않는다. -mx
에
의해 지정된 양을 보유하면서 커밋 될 수 있는 것으로 전체 범위의 주소를 표시한다. 그런 다음 메모리의 일부만 커밋하는데 이것은
메모리 매니저가 실제 메모리와 페이징 파일에서 페이지를 할당하여 백업하는데 필요한 부분을 위한 것이다. 나중에 활성 데이터의
양이 늘어나고 힙이 확장되어야 한다면 JVM은 현재 커밋된 영역에 인접하여 약간 더 커밋할 수 있다. 이러한 방식으로 JVM은
하나의 인접한 힙을 관리하면서 필요할 때 늘릴 수 있다. (참고자료)
물리적 스토리지는 일반적으로 알려져 있는 동일한 크기 단위인 페이지 프레임(page frame)으로 구성된다. 페이지 테이블(page table) 이라고 하는 운영 체계 데이터 구조는 애플리케이션이 접근한 가상 페이지들을 주 메모리의 실제 페이지로 매핑한다. 맞을 수 없는 페이지들은 디스크상의 임시 페이징 파일에 저장된다. 페이지가 메모리상에 없는 페이지로 접근을 시도할 때, 페이지 오류(page fault)는 메모리 매니저로 하여금 페이징 파일에서 이를 검색하도록 하여 이를 다시 주 메모리에 놓는다. 이 작업을 페이징(paging)이 라고 한다. 어떤 페이지가 교체되어야 하는지를 결정하는데 사용되는 이 세밀한 알고리즘은 Windows 버전에 따라 다르다. Windows에서는 페이지 프레임이 여러 애플리케이션들이 한번에 사용하는 프로세스들간(예를 들어, DLL) 공유되도록 한다. Windows는 다른 주소 공간의 많은 가상 페이지들을 같은 물리적 위치로 매핑하여 이를 수행한다.
애플리케이션은 이 모든 액티비티를 감쪽같이 모르고 있다. 알고 있는 것이라곤 자신의 가상 주소 공간이다. 하지만 상주 세트(resident set)로 알려진 주 메모리의 페이지 세트가 작업 세트(working set)로 알려진 실제 사용에 필요한 페이지 세트 보다 작을 경우 퍼포먼스가 떨어지게 된다.
![]() |
![]()
|
이제 가장 일반적인 두 개의 툴인 Task Manager와 PerfMon을 살펴보도록 하겠다. Windows에 번들되어 있다.
Task Manager는 매우 단순한 Windows 프로세스 모니터이다. Ctrl-Alt-Delete 키 조합이나 Taskbar를 오른쪽 클릭하여 액세스 할 수 있다. Processes 탭에서 상세한 정보를 보여주고 있다.(그림 2)
그림 2의 컬럼들은 View > Select Columns를 선택하여 커스터마이징 되었다. 어떤 컬럼 헤딩 이름이 모호하지만 Task Manager 도움말에 각각의 정의가 나와있다. 프로세스의 메모리 사용에 대한 가장 연관이 깊은 것은 다음과 같다:
비 록 Windows 문서가 Mem Usage를 작업 세트로 언급한다 하더라도 이 글에서는 상주 세트로 통칭하도록 하겠다. Memory Management Reference's glossary에서 이 용어에 대한 자세한 정의를 참고하기 바란다. (참고자료) 작업 세트(Working set)는 프로세스가 어떤 페이징이라도 피하기 위해 그 지점에서 메모리에 갖고 있어야 할 페이지들의 논리적 개념을 의미한다.
또 다른 툴로는 PerfMon이 있다. 이것은 프린트 큐부터 전화 기술 까지 광범위한 카운터를 감시한다. PerfMon은 일반적으로 시스템 경로에 있기 때문에 명령행에서 perfmon
을 입력하여 시작할 수 있다. 이 툴의 장점은 카운터를 그래픽으로 디스플레이 한다는 것이다. 따라서 시간의 흐름에 따라 변하는 방법을 쉽게 볼 수 있다.
PerfMon 스크린의 상단에 있는 툴바에서 + 버튼을 클릭한다. 대화창이 나오고 검사 할 카운터를 선택할 수 있다. (그림 3a) 카운터는 퍼포먼스 객체들로 알려진 범주들로 그룹핑된다. 메모리 사용과 관련된 두 가지는 Memory와 Process이다. 카운터 정의는 Explain버튼을 클릭한다. 개별 창에 설명이 나온다.(그림 3b)
(Ctrl을 사용하여 여러 열들을 하이라이트 하여) 관심 있는 카운터를 선택하고 모니터 하려는 인스턴스를 선택한다. 그런다음 Add를 클릭한다. 이 툴은 즉시 선택한 모든 카운터들의 값을 디스플레이 하기 시작한다. 리포트, 시간 별 그래프, 히스토그램으로 나타낼 수 있다. 그림 4는 히스토그램 디스플레이이다.
그래프 보기를 원하지 않으면 그래프 영역에서 오른쪽 클릭을 하여 Properties를 선택하여 스케일을 변경해야 할 것이다. 그런다음 Graph 탭으로 움직인다. 특정 카운터의 스케일을 변경하려면 Data 탭으로 간다.
카운터
불행히도 PerfMon은 Task Manager와 다른 용어를 사용한다. 표 1은 가장 유용한 카운터를 요약한 것이다:
카운터 이름 | 범주 | 설명 | Task Manager equivalent |
Working Set | Process | Resident set - 실제 메모리에 얼마나 많은 페이지들이 있는가? | Mem Usage |
Private Bytes | Process | 메모리를 나타내는 할당된 총 프라이빗 가상 메모리 | VM Size |
Virtual Bytes | Process | 공유된 페이지를 포함하여 가상 주소 공간의 총 크기. Reserved 메모리를 포함하기 때문에 이전 두 개의 값들 보다 훨씬 더 클 수 있다. | -- |
Page Faults / sec | Process | 초당 발생했던 페이지 오류의 평균 수 | Page Faults로 링크됨 |
Committed Bytes | Memory | "committed" 상태에서 가상 바이트의 총 수 | -- |
C로 작성한 작은 프로그램을 다운로드 및 실행하면 Task Manager와 PerfMon에서 이러한 양(quantity)이 어떻게 나타나는지 알 수 있다. (Download 섹션 참조) 이 프로그램은 Windows VirtualAlloc
호출을 사용하여 우선 메모리를 보유(reserve)한 다음 커밋한다. 마지막으로 메모리 일부를 관여하기 시작하고 매 4,096
바이트마다 값을 작성하면서 페이지를 작업 세트로 가져간다. 프로그램을 실행하고 Task Manager 또는 PerfMon을
사용하여 이를 본다면 값 변경 사항을 볼 수 있다.
![]() |
![]()
|
애플리케이션이 얼마나 많은 메모리를 사용하고 있는지 알았다면 이제는 실제 메모리 내용을 상세하게 볼 차례이다. 이 섹션에서는 좀더 세련된 툴을 소개하도록 하겠다. 적절한 사용 시점과 아웃풋을 인터프리팅하는 방법을 설명하겠다.
우선 PrcView 툴을 설명하겠다. (참고자료) 많은 작업에 이 툴이 사용된다. 속성을 설정하고 프로세스를 죽일 수 있고, 머신 상에 프로세스의 속성을 나열하는 유용한 명령행 버전으로 존재한다. 풋프린트에서 보기위해 이를 어떻게 사용하는지 설명하겠다.
PrcView를 시작하면 Task Manager 같이 생긴 프로세스가 시스템에 나타난다. 스크롤을 이용하면 자바 프로세스가 하이라이트 되면 스크린은 그림 5 처럼 보인다.
자바 프로세스에서 오른쪽을 클릭하여 팝업 메뉴를 띄우거나 상단 메뉴 바에서 Process를 선택하면 프로세스에 관한 몇 가지 사항들을 검사할 수 있다. 프로세스가 갖고 있는 쓰레드와 로딩한 DLL 등이 나타난다. 그리고 이것을 죽이거나 속성을 설정할 수도 있다. 우리가 관심 있는 옵션은 메모리 검사이다. 그림 6을 참조하라.
PrcView 가 디스플레이하는 주소-공간 지도가 나온다. 첫 번째 줄은 주소 0 부터 이고 길이는 65,536 (64K)이며 메모리는 Free 이다. 어떤 것도 할당된 것은 없고 주소도 사용 될 수 없다. 그 다음에 바로 시작한 두 번째 라인은 주소는 0x00010000이고 길이는 커밋 된 메모리의 8,192-byte(두 개의 4K 페이지) 이다. 메모리는 어드레스 될 수 있고 페이징 파일에서 페이징 프레임의 지원을 받는다. 또 다른 free 확장 그런다음 커밋 된 확장 등으로 이어진다.
이 주소 공간의 영역 중 어떤 것도 당신에겐 의미가 없다. Windows에 의해 사용되기 때문이다. Windows 주소 공간을 설명하고 있는 Microsoft 문서는 이들은 MS-DOS 호환성을 위해 보유된 다양한 영역들이고 사용자 데이터와 코드용 영역은 4MB 에서 시작함을 언급하고 있다. (참고자료)
스크롤을 아래로 내려보면 확실히 인식할 수 있는 주소 공간에서 무엇인가에 다다르게 된다. (그림 7)
그림 7에서, 강조된 라인과 그 바로 밑에 것은 자바 힙에 상응한다. 여기에서 시작했던 자바 프로세스는 1000MB 힙 (-mx1000m
사용)이 주어졌다. 이는 해당 프로그램에 있어 엄청나게 큰 것으로서 PrcView 맵에서 확실히 나타나있다. 강조된 라인은 힙의
커밋된 부분을 단 4MB로 보여주고 있으며 주소 0x10180000에서 시작한다. 강조된 라인 바로 밑에는 큰 reserved
확장인데 이것은 아직 커밋되지 않은 나머지 힙이다. 시작 시 JVM은 초기에 총 1000MB를 보유하고
있다.(0x10180000 에서 0x4e980000 까지의 주소범위를 사용 불가로 만든다.) 그리고 시작하는데 필요한 것을
커밋한다. 이 경우 4MB 이다. 이 값이 현재 힙 사이즈에 상응한다는 것을 확인하려면 -verbosegc
JVM 옵션으로 자바 프로그램을 호출한다. 그러면 가비지 컬렉터에서 자세한 정보가 프린트 된다. -verbosegc
아웃풋에 있는 두 번째 라인의 두 번째 GC 에서 현재 힙 사이즈가 대략 4GB라는 것을 볼 수 있다:
>java -mx1000m -verbosegc Hello |
-verbosegc
아웃풋 포맷은 우리가 사용하는 JVM 포맷에 의존한다. (참고자료)
활 성 데이터의 양이 늘어나고 JVM이 4GB 이상으로 힙을 확장해야 하는 경우 RESERVED 영역 그 이상으로 커밋한다. 새로운 영역은 0x10580000에서 시작한다는 것을 의미하며 이미 커밋 된 힙 메모리와 연결된다는 것을 의미한다.
그림 7의 PrcView 스크린의 마지막 세 줄은 프로세스의 총 커밋 메모리를 보여주고 있다. 7 번째 칼럼(Type)에서 총합이 계산된다:
지금 까지, 크기에 기반하여 주소 공간 안에 힙을 배치했다. 메모리의 다른 영역이 어떤 것이 있는지를 이해하려면 메모리 안을 자세히 들여다 보는 것이 필요하다.
TopToBottom은 smidgeonsoft.com에서 무료로 사용할 수 있다. (참고자료) 해당 문서는 없지만 현재 실행하는 프로세스를 포괄적으로 볼 수 있다. 이름과 프로세스 ID 뿐만 아니라 시작 시간 별로 프로세스를 소팅할 수 있다. 때문에 프로그램이 시작한 순서를 이해할 때 유용하다.
그림 8은 생성 시간에 따라 소팅한 프로세스 리스트로 TopToBottom을 보여주고 있다. (View > Sort > Creation Time)
StartUp 탭은 자바 프로세스를 생성했던 프로세스, 이것이 시작한 시간과 날짜, 이를 호출 할 때 사용한 실제 명령행, 실행 파일과 현재 디렉토리로의 전체 경로를 디스플레이하고 있다. Environment 탭을 클릭하면 시작 시 프로세스로 전달되었던 모든 환경 변수의 값을 디스플레이한다. Modules 탭은 자바 프로세스가 사용중인 DLL을 보여주고 있다.(그림 9)
다 시, 다양한 방법으로 이 리스트를 소팅할 수 있다. 그림 9에서 초기화 순서 별로 소팅되고 있다. 열을 더블 클릭하면 DLL에 대한 자세한 정보를 볼 수 있다: 주소와 크기, 작성 날짜와 시간, 의존하고 있는 다른 DLL 리스트, DLL을 로딩했던 모든 실행 프로세스 리스트. 리스트를 검토하면 NTDLL.DLL 같은 DLL을 볼 수 있는데 이는 모든 실행 프로세스에 필요한 것이다; JVM.DLL 같은 DLL은 모든 자바 프로세스들간 공유된다; 다른 것들은 하나의 프로세스에 의해 사용된다.
개 별 DLL의 크기를 추가하여 프로세스가 사용하고 있는 DLL의 전체 크기를 알아낼 수 있다. 하지만 결과 숫자는 프로세스가 그 모든 프로세스를 소비하고 잇다는 것을 의미하는 것이 아니기 때문에 오도될 수 있다. 진짜 크기는 프로세스가 실제로 사용하고 있는 DLL의 일부에 의존한다. 그러한 부분은 프로세스의 작업 세트에 의존한다. 이는 분명해 보이지만 DLL은 읽기 전용이고 공유 된다. 많은 프로세스들이 모두 주어진 DLL을 사용한다면 단 한 세트의 실제 메모리 페이지만이 어떤 한 시간에 DLL을 보유하게 된다. Task Manager 같은 툴들은 작업 세트를 공유된 페이지들과 공유되지 않은 페이지들의 총합으로 보고하여 풋프린트에서 DLL이 사용의 실제 효과를 결정하기 힘들다. 모듈 정보는 DLL 때문에 기인한 풋프린트의 "최악의 경우"를 볼 수 있는 유용한 방법이다. 이것은 필요할 경우 다른 툴들을 사용하여 자세한 분석이 이루어져 다듬어진다.
메모리 풋프린트에 관심이 있으면 Memory 탭을 클릭한다. 그림 10은 자바 프로그램이 사용하고 있는 모든 메모리의 하위 세트이다.
PrcView 와 비슷하다. 하지만 가상 주소 공간의 커밋된 메모리만 보여주고 있다. 보유된 메모리는 없다. 하지만 두 개의 장점이 있다. 하나는, 페이지들을 좀더 자세하게 특징지을 수 있다. 예를 들어 그림 10에서 Thread 3760 스택 영역을 그저 읽기/쓰기 데이터가 아닌 구체적으로 구분했다. 이것이 인식하는 추가 데이터 영역들에는 Environment, Process Parameters, Process Heap, Thread Stack, Thread Environment Block(TEB)이 포함된다. 두 번째, TopToBottom에서 직접 메모리를 검색할 수 있다. 텍스트 스트링을 검색하거나 16 바이트까지 시퀀스의 16진수 검색을 할 수 있다. 16진수 검색을 특정 정렬까지 제한할 수 있는데 이는 주소에 대한 레퍼런스를 검색할 때 유용하다.
TopToBottom은 또한 스냅샷 장치가 있어서 프로세스에 대한 모든 정보를 클립보드에 덤핑할 수 있다.
VADump는 편리한 명령행 툴로서 패키지의 일부이다. (참고자료) 가상 주소 공간 개요와 특정 프로세스의 상주 세트를 덤핑하는 용도이다. VADump를 사용하는 가장 간단한 방법은 명령행에 다음 명령어를 입력한다:
vadump process_id |
process_id는 당신이 관심을 갖고 있는 프로세스의 수이다. 인자 없이 VADump를 호출하여 전체 사용 정보를 디스플레이 할 수 있다. 아웃풋을 파일에 파이프(pipe) 할 것을 권장한다. (예를 들어, vadump
1234 > output.txt
)VADump는 스크린이 감당하기엔 너무 많은 정보를 만들기 때문이다.
아웃풋은 인덱스를 프로세스를 위한 가상 주소 공간으로 보여주는 것으로 시작한다:
>vadump -p 3904 |
(읽기 쉽도록 아웃풋 내용을 잘랐다.)
각 블록 마다 다음 정보를 볼 수 있다:
그런 다음 사이즈 포함하여 프로세스에 의해 사용중인 모든 DLL 리스트를 보여주고 그 다음 작업 세트와 페이지 파일 사용에 대한 정보 요약이 나온다.
지금 까지, 이 정보는 다른 툴로도 사용할 수 있다. VADump의 -o
옵션을 사용하면 더 많은 아웃풋을 만들 수 있다. 현재 작업 세트의 스냅샷을 만들어 낸다. (이 페이지는 실제로 정해진 시간에
주어진 지점에 주 메모리에 있는 페이지이다.) 이 옵션의 문서화는 형편없지만 상주 세트에서 가장 중요한 컴포넌트가 무엇인지
파악하는데 매우 유용하다. 따라서 메모리 최적화의 강력한 후보이다. 메모리 유출을 확인할 때도 사용할 수 있다. 규칙적인
간격으로 스냅샷을 찍는다. 이 모드에서 아웃풋은 가상 주소 공간에서 커밋 페이지의 자세한 덤프로 시작한다. 현재 주 메모리에
있는지의 여부는 상관없다:
>vadump -o -p 3904 |
긴 목록의 끝까지 스크롤을 내리면 좀더 자세한 정보가 나온다: 주 메모리에 현재 상주하고 있는 프로세스의 페이지용 페이지-테이블 매핑 리스트이다:
0xC0000000 > (0x00000000 : 0x003FFFFF) 132 Resident Pages |
이들 매핑 각각은 페이지 테이블의 싱글 엔트리에 상응한다. 따라서 추가 4KB를 이 프로세스용 작업 세트에 기여한다. 이 매핑으로 애플리케이션의 어떤 부분이 가장 많은 메모리를 사용하고 있는지 파악하기 어렵지만 다음 아웃풋에 유용한 요약이 있다:
Category Total Private Shareable Shared |
두 개의 가장 흥미로운 값들은 일반적으로 Heap이다. 이것은 Windows 프로세스 힙과 Other Data이다. Windows API 호출을 통해 직접 할당된 메모리는 프로세스 힙의 일부를 형성하고 Other Data에는 자바 힙이 포함된다. Grand Total Working Set는 Task Manager의 Mem Usage와 Tab 필드와 코릴레이션 한다. 이것은 내부 Windows 구조인 프로세스의 Thread Environment Block에 필요한 메모리이다.
마지막으로 VADump -o
아웃풋 밑에는 DLL, 힙, 쓰레드 스택에서 작업 세트로의 기여를 요약된다:
Module Working Set Contributions in pages |
이 모드에서 VADump를 사용하여 두 개 이상의 자바 프로세스의 결합 풋프린트에 대한 정확한 뷰를 얻을 수 있다. (팁 섹션 참조)
그러나 메모리 분석을 위한 좀더 유용한 툴들은 Sysinternals에서 제공한다. (참고자료) 이중 하나는 그래픽 프로세스 익스플로러(그림 11)이다. Task Manager의 훌륭한 대체품이다.
Process Explorer는 Task Manager와 기능이 모두 같다. 예를 들어, 전체 시스템 퍼포먼스에 대한 동적 그래프를 볼 수 있다. (View > System Information...)그리고 비슷한 방식으로 주 프로세스 뷰에 있는 칼럼들을 설정할 수 있다. Process > Properties...이 하에서, Process Explorer는 이 프로세스에 대한 자세한 정보를 제공한다. 전체 경로와 명령행, 쓰레드, CPU 사용에 대한 동적 그래프, 프라이빗 바이트 등이 그것이다. 사용자 인터페이스는 그림 11에서 보듯 우수하다. DLL 상의 정보를 검색할 수 있고 프로세스를 위해 한들 할 수 있다. Options > Replace Task Manager를 사용하여 Task Manager 대신 Process Explorer를 실행할 수 있다.
Sysinternals 명령행 유틸리티인 ListDLLs와 Handle을 다운로드 할 수 있다. 메모리 모니터링 형식을 스크립트나 프로그램으로 결합할 때 특히 유용하다.
ListDLLs 로 DLLs를 볼 수 있다. 이것은 메모리 풋프린트에 중대한 기여를 한다. 이것을 사용하려면 경로에 이것을 추가하여 help 옵션으로 이것을 호출하여 사용 정보를 얻는다. 프로세스 ID와 이름으로 호출할 수도 있다. 다음은 자바 프로그램이 사용하는 DLL 리스트이다:
>listdlls -r 3904 |
또는 listdlls -r java
명령어를 사용하면 실행중인 모든 자바 프로세스와 이들이 사용하고 있는 DLL을 보여준다.
Handle은 프로세스가 사용하고 있는 모든 (파일과 소켓에 대한) Handle을 보여준다. Handle 다운로드 파일의 압축을 풀어 이를 경로에 추가한다. 자바 프로그램상에서 실행하면 다음과 같은 아웃풋을 만들어 낸다:
>handle -p 3904 |
이 프로세스가 클래스 경로상의
디렉토리와 여러 JAR 파일에 대한 handle을 갖고 있다는 것을 알 수 있다. 사실 프로세스는 훨씬 더 많은 handle을
갖고 있다. 하지만 기본적으로 이 유틸리티는 파일을 참조하는 handle만 보여준다. -a
매개변수를 사용하여 다른 것들도 디스플레이 할 수 있다zzzzz:
>handle -a -p 3904 |
메모리에 관심을 갖고 있다면 각 handle이 특정 공간을 소비하기 때문에 handle은 중요하다. 정확한 양은 운영 체계 버전과 handle의 유형에 따라 다르다. 일반적으로 handle은 풋프린트에 중요한 영향을 끼치지 않는다. 이 유틸리티가 만들어내는 라인의 수를 세기만 해도 handle의 수가 중요하거나 늘어나고 있다는 것을 빠르게 볼 수 있다.
![]() |
![]()
|
여기에서 제시한 모든 툴을 다루는데 자신이 생겼으리라 믿고 여기에 메모리 모니터링을 향상시킬 유용한 방법을 소개하겠다.
애플리케이션의 프로세스 ID를 찾아서 VADump 같은 명령행 툴에서 사용하려면 Task Manager의 Applications 탭을 열어 관심 있는 프로세스를 더블 클릭한다. Go To Process를 선택한다. Processes 탭에서 ID를 볼 수 있다.
java 또는 javaw 이름이 붙은 모든 프로세스 리스트가 헷갈린다면 어떤 것을 검사하고 싶은지 파악하려고 하는가? 자바 프로세스가 IDE 또는 스크립트에서 시작되었다면 어떤 JVM이 사용 중이고 어떤 명령행 매개변수가 자바 프로세스로 보내지는지 결정하기 힘들다. 이 정보는 TopToBottom Startup 탭에서 쉽게 사용할 수 있다. JVM을 호출하는데 사용되는 전체 명령행과 프로세스가 시작된 시간을 볼 수 있다.
다 른 프로세스에 의해 사용 중이라는 정보를 얻도록 파일을 저장해 본 적이 있는가? 해당 프로그램을 닫을 때 에러 메시지가 여전히 뜨는 것을 경험했는가? SysInternals Process Explorer 툴의 Handle Search 장치를 사용하여 문제를 찾을 수 있다. Search 대화창을 열어 파일의 이름을 입력한다. ProcExp는 모든 개방 handle을 검색하고 프로세스를 구분한다. 종종 사용자 인터페이스를 닫은 후에 에디터나 웹 브라우저에 남아 실행되는 스텁 프로세스로 드러난다.
VADump의 -o
옵션을 사용하여 프로세스의 현재 작업 세트에 무엇이 있고 얼마나 많이 공유되는지 파악할 수 있다. 시스템 상에서 실행중인 하나의
자바 프로그램 덤프를 가져다가 또 다른 것을 시작하고 다시 덤프를 갖는다. 각 요약에서 Code/StaticData 값을
비교하면 "Shareable" 바이트가 "Shared" 가 되어있음을 발견한다.
Windows 는 사용하지 않는 것으로 드러난 프로세스의 상주 세트를 다듬는(trimming)" 정책을 구현한다. Task Manager의 Processes 탭을 열어 검사하고 있는 애플리케이션의 프로세스를 볼 수 있다. 그런 다음 애플리케이션 윈도우를 최소화한다. Mem Usage 필드에 어떤 일이 발생하는지 관찰하라!
Windows Server 2003과 Windows NT의 경우, Microsoft는 ClearMem이라고 하는 재미있는 유틸리티를 제공한다. Windows에서 앞으로 애플리케이션이 메모리를 더 사용할지 검사하고자 할 때 유용하다. (참고자료) 이 툴은 실제 메모리의 크기를 결정하고 소비할 충분한 메모리를 할당하여 할당된 메모리를 최대한 빨리 파악하여 릴리스한다. 이것은 다른 애플리케이션의 메모리 소비에 압력을 주고 여러 번 ClearMem을 실행할 때의 효과는 애플리케이션이 사용하고 있는 메모리의 양을 최소한의 값으로 떨어뜨린다.
![]() |
![]()
|
이 글에서 Windows가 메모리를 어떻게 관리하는지를 요약했고 자바 프로그램의 메모리 사용을 감시하는데 사용할 수 있는 무료 툴들을 소개했다. 웹이나 상용 오퍼링에서 무료로 다운로드 할 수 있다. 하지만 충분한 지식으로 무장하기 바란다. 무엇이 측정되고 있는지에 대해 정확히 알려면 꾸준힌 실험을 하는 것 뿐이다.
물론, 이러한 툴들은 문제를 확인할 때만 도움이 된다. 이를 해결하는 것은 여러분의 몫이다. 자바 힙이 메모리의 가장 큰 부분을 차지하고 있다는 것을 알게 될 것이다. 코드를 자세히 검토하여 객체 레퍼런스가 필요한 것 이상을 보유하고 잇는지 확인해야 한다. 많은 유용한 툴들과 자료들을 참고자료 섹션에서 참조하기 바란다.
![]() |
![]()
|
설명 | 이름 | 크기 | 다운로드 방식 |
---|---|---|---|
A C program to demonstrate how Windows uses memory | experiment.c | 3KB | FTP |
![]() | ||||
![]() | 다운로드 방식에 대한 정보 | ![]() |
![]() | ||
![]() | Emma Shepherd, 소프트웨어 엔지니어, IBM UK Labs |
![]() | ||
![]() | Martin Trotter, 소프트웨어 엔지니어, IBM UK Labs |
![]() | ||
![]() | Caroline Maynard, 소프트웨어 엔지니어, IBM UK Labs |
![]() | ||
![]() | Matthew Peters, 소프트웨어 엔지니어, IBM UK Labs |
SSISO Community