2011년 12월 26일 월요일

[DeveloperWorks] 덤프를 이용한 디버깅

덤프를 이용한 디버깅



요약:  Memory Analyzer는 Java™ 프로세스의 덤프를 사용하여 메모리 손실과 풋프린트 문제점을 진단할 수 있는 강력한 도구입니다. 또한, 이 도구는 사용 중인 Java 코드에 대한 자세한 정보를 제공하며 이 도구를 이용하면 진단 코드를 삽입하지 않고도 하나의 덤프만으로 까다로운 문제점을 일부 디버깅할 수 있습니다. 이 기사에서는 덤프를 생성한 후, 이 덤프를 사용하여 애플리케이션의 상태를 조사하는 방법을 배웁니다.


코드에 디버깅 문을 추가하여 오브젝트나 전체 데이터 콜렉션의 해당 필드를 완전히 다시 작성하는 것이 일반적인 문제 해결 방식이다. 문제점을 이해하고 해결하려면 더욱 더 많은 정보가 필요하기 때문에 때로는 이러한 작업을 반복해서 수행해야 한다. 이러한 프로세스가 효과적이라고 해도 원하는 결과를 얻을 수 없을 때도 있다. 디버그 코드가 너무 많아서 문제점이 표시되지 않을 수 있고, 자신이 작성하지 않은 코드에 디버그 문을 추가해야 할 수도 있으며, 디버깅을 하려면 프로세스를 다시 시작해야 하거나 디버그 문이 전체 성능에 미치는 영향으로 인해 애플리케이션을 실행하기 어려울 수도 있다.
Memory Analyzer는 메모리 문제점을 진단할 때뿐만 아니라 전체 Java 애플리케이션의 상태와 작동에 대한 정보를 얻으려 할 때도 사용할 수 있는 크로스 플랫폼 오픈 소스 도구이다. Memory Analyzer는 애플리케이션이 실행되고 있는 동안 Java 런타임에서 작성된 스냅샷 덤프를 읽어서, 디버그 코드로 확인할 수 없는 까다로운 문제점을 진단할 수 있는 방법을 제공한다.
이 기사에서는 덤프를 생성한 후, 이 덤프를 사용하여 애플리케이션의 상태를 조사하고 진단하는 방법을 배운다. Memory Analyzer를 사용하면 스레드, 오브젝트, 번들 및 전체 데이터 콜렉션을 조사하여 메모리 손실을 비롯한 Java 코드의 문제점을 디버깅할 수 있다.
스냅샷 덤프 유형
현재 Memory Analyzer는 다음과 같은 세 가지 덤프 유형에서 작동한다.
  • IBM PHD(Portable Heap Dump): IBM의 이 사설 형식에는 처리 중인 각 Java 오브젝트의 유형과 크기 및 이 오브젝트 간의 관계만 포함되어 있다. 이 덤프 파일 형식은 다른 형식보다 상당히 작고 최소한의 정보만 포함하고 있다. 그렇지만 메모리 손실을 진단하고 애플리케이션의 아키텍처와 풋프린트를 기본적으로 이해하는 데는 이 데이터로도 충분하다.
  • HPROF 2진 덤프: HPROF 2진 형식에는 IBM PHD 형식에 있는 모든 데이터뿐만 아니라 Java 오브젝트 내부에 있는 원시 데이터와 스레드 세부사항이 들어 있다. 오브젝트 안의 필드에 있는 값을 조사할 수 있으며 덤프를 수행한 시점에서 어떤 메소드가 실행 중이었는지 확인할 수 있다. 원시 데이터가 추가되었기 때문에 HPROF 덤프는 PHD 형식의 덤프보다 상당히 더 크며 덤프의 크기는 사용된 Java 힙의 크기와 거의 비슷하다.
  • IBM 시스템 덤프: IBM Java 런타임을 사용 중인 경우에는 원시 운영 체제 덤프 파일(AIX® 또는 Linux의 코어 파일, Windows®의 minidump 또는 z/OS®의 SVC 덤프)을 Memory Analyzer로 로드할 수 있다. 이러한 덤프에는 실행 중인 애플리케이션의 전체 메모리 이미지, 즉 HPROF 형식의 모든 정보와 데이터뿐만 아니라 모든 원시 메모리 및 스레드 정보가 들어 있다. 이 형식이 가장 크고 포괄적인 덤프 파일 형식이다.
두 가지 IBM 덤프 유형은 모두 DTFJ(Diagnostic Tool Framework for Java) 플러그인을 설치한 경우에만 사용 가능하다. (참고자료Memory Analyzer 변종을 참조한다.)
표 1에는 덤프 파일 유형 간의 차이점이 요약되어 있다.

표 1. 덤프 유형의 특성 요약
덤프 유형 디스크에서의 대략적 크기 오브젝트, 클래스 및 클래스 로더 스레드 세부사항 필드 이름 필드 및 배열 참조 원시 필드 원시 배열 컨텐츠 정확한 가비지 콜렉션 루트 원시 메모리 및 스레드
IBM PHD Java 힙 크기의 20% Y Javacore와 함께* N Y N N N N
HPROF Java 힙 크기 Y Y Y Y Y Y Y N
IBM 시스템 덤프 Java 힙 크기 + 30% Y Y Y Y Y Y Y Y
*동시에 생성된 javacore.txt 파일(IBM 스레드 덤프 파일)과 heapdump.phd 파일을 모두 Memory Analyzer에서 로드하면 IBM PHD 형식 덤프에서 스레드 세부사항을 확인할 수 있다.
HPROF와 IBM 시스템 덤프 형식은 운영 체제에 있는 도구를 사용하여 원래 크기의 약 20%로 압축할 수 있다.

스냅샷 덤프 얻기
다양한 메커니즘을 사용하여 각 Java 런타임을 대상으로 다양한 덤프를 얻을 수 있으며, 이렇게 하면 OutOfMemoryError와 관련된 시나리오 이외의 다양한 시나리오에서 스냅샷 덤프를 유연하게 생성할 수 있다. 사용 가능한 메커니즘은 어떤 벤더의 Java 런타임을 사용 중인지에 따라 달라진다.
선수조건
모든 덤프 유형에서 덤프가 잘리지 않도록 덤프에 필요한 충분한 디스크 공간을 확보해야 한다. 덤프의 기본 위치는 JVM 프로세의 현재 작업 디렉토리이다. IBM JVM에서는 -Xdump 파일 명령행 옵션을 사용하여 이 작업 디렉토리를 변경할 수 있다. HotSpot JVM에서는 -XX:HeapDumpPath 명령행 옵션을 사용하여 이 디렉토리를 변경할 수 있다. 관련 구문을 가리키는 링크는 참고자료를 참조한다.
운영 체제에서 생성된 덤프는 IBM JVM과 HotSpot JVM 모두에서 사용할 수 있다. IBM JVM에서는 JDK와 함께 제공되는 jextract 도구를 사용하여 덤프를 생성하여 Memory Analyzer로 로드할 수 있으며 HotSpot JVM에서는 jmap 도구를 사용하여 코어 덤프에서 힙 덤프를 추출할 수 있다. (이 두 가지 기술은 이 기사에서 나중에 설명한다.) 그러나 일부 운영 체제에서는 코어 덤프를 생성하기 전에 프로세스가 ulimit이 충분한 상태에서 실행 중인지 확인해야 하며, ulimit이 충분하지 않은 경우에는 코어 덤프가 잘리고 분석이 제한되게 된다. ulimit이 올바르지 않은 경우에는 덤프를 수집하기 전에 이 값을 수정한 후, 프로세스를 다시 시작해야 한다. AIX, Linux®, z/OS 및 Solaris에서 시스템 덤프를 얻는 방법에 관한 자세한 정보를 가리키는 링크는 참고자료를 참조한다.
스냅샷 덤프 얻기: HotSpot 런타임
HotSpot 기반의 Java 런타임은 HPROF 형식의 덤프만 생성한다. 여러 가지 대화식 방식과 한 가지 이벤트 기반 방식 중에서 선택하여 덤프를 생성할 수 있다.
  • 대화식 방식
    • Ctrl+Break 사용: 실행 중인 애플리케이션에 -XX:+HeapDumpOnCtrlBreak 명령행 옵션이 설정된 경우에는 Ctrl+Break 이벤트 또는 SIGQUIT(일반적으로 kill -3을 사용하여 생성)이 콘솔을 통해 전송될 때 HPROF 형식의 덤프가 스레드 덤프와 함께 생성된다. 이 옵션은 일부 버전에서는 사용할 수 없으며 이러한 경우에는 다음과 같이 한다.
      -Xrunhprof:format=b,file=heapdump.hprof
    • jmap 도구 사용: JDK의 bin 디렉토리에 있는 jmap 유틸리티 도구(참고자료 참조)는 실행 중인 프로세스의 HPROF 덤프를 요청할 수 있는 옵션을 제공한다. Java 5를 사용하는 경우에는 다음 명령을 사용한다.
      jmap -dump:format=b pid

      Java 6을 사용하는 경우에는 다음 버전을 사용한다. 여기서 live는 옵션이며 이 옵션을 지정하면 "실시간" 오브젝트만 덤프 파일 프로세스 ID(PID)로 쓰여진다.
      jmap -dump[live,]format=b,file=filename pid
    • 운영 체제 사용: 비파괴적인 gcore 명령이나 파괴적인 kill -6 또는 kill -11 명령을 사용하여 코어 파일을 생성한다. 그런 다음, 다음과 같이 jmap을 사용하여 코어 파일에서 힙 덤프를 추출한다.
      jmap -dump:format=b,file=heap.hprof path to java executable core
    • JConsole 도구 사용: dumpHeap 조작은 JConsole의 HotSpotDiagnostic MBean 아래에서 제공된다. 이 조작은 HPROF 덤프를 생성하도록 요청한다.
  • 이벤트 기반 방식
    • OutOfMemoryError의 경우: 실행 중인 애플리케이션에 -XX:+HeapDumpOnOutOfMemoryError 명령행 옵션을 설정한 경우에는 OutOfMemoryError가 발생하면 HPROF 형식의 덤프가 생성된다. 메모리 관련 문제점을 진단하려면 거의 언제나 이러한 과정을 거쳐야 하고 이로 인해 성능상의 오버헤드가 발생하지도 않으므로 프로덕션 시스템에서는 이러한 기능이 제대로 작동하는 것이 좋다. HotSpot 기반 Java 런타임의 이전 릴리스에서는 JVM을 실행될 때마다 이러한 이벤트 시에 생성되는 힙 덤프의 양에 제한이 없었지만, 최신 릴리스에서는 JVM이 실행될 때마다 이러한 이벤트 시에 최대한의 힙 덤프가 생성된다.
스냅샷 덤프 얻기: IBM 런타임
IBM 런타임은 많은 대화식 시나리오와 이벤트 기반 시나리오를 통해 PHP 형식이나 시스템 덤프를 생성할 수 있는 추적 엔진과 덤프를 제공한다. Health Center 도구를 사용하거나 프로그램 방식으로 Java API를 사용하여 대화식 덤프를 생성할 수도 있다.
  • 대화식 방식
    • SIGQUIT 또는 Ctrl+Break 사용: Ctrl+Break나 SIGQUIT(일반적으로 kill -3을 사용하여 생성)이 IBM 런타임에 전송되면 IBM 덤프 엔진에서 사용자 이벤트가 생성된다. 기본적으로 이 이벤트는 스레드 덤프 파일(javacore.txt)만 생성한다. -Xdump:heap:events=user 옵션을 사용하여 PHD 형식의 덤프를 생성하거나 -Xdump:system:events=user 옵션을 사용하여 Java 애플리케이션의 시스템 덤프를 생성할 수 있다.
    • 운영 체제를 사용하여 시스템 덤프 생성:
      • AIX: gencore(또는 파괴적인 kill -6 또는 kill -11)
      • Linux/Solaris: gcore(또는 파괴적인 kill -6 또는 kill -11)
      • Windows: userdump.exe
      • z/OS: SVCDUMP 또는 콘솔 덤프
    • IBM Monitoring and Diagnostics Tools for Java 사용 - Health Center: Health Center 도구에는 실행 중인 Java 프로세스의 PHD나 시스템 덤프를 요청할 수 있는 메뉴 옵션이 있다(참고자료 참조).
  • 이벤트 기반 방식. IBM 덤프와 추적 엔진은 throw 명령으로 처리한 예외에서부터 실행된 메소드에 이르기까지 다양한 이벤트가 발생했을 때 PHD와 시스템 덤프를 생성할 수 있는 유연한 기능 세트를 제공한다. 이러한 도구를 사용하면 진단하고자 하는 문제점이 발생하는 대부분의 상황에서 덤프를 생성할 수 있다.
    • IBM 덤프 엔진 사용: 이 덤프 엔진은 PHD나 시스템 덤프를 생성할 수 있는 많은 이벤트를 제공한다. 게다가 이 엔진을 사용하면 이러한 이벤트 유형을 필터링하여 덤프를 생성하는 시점을 더욱 세밀하게 제어할 수 있다.
      -Xdump:what 옵션을 사용하여 기본 이벤트를 확인할 수 있다. 예를 들면, JVM에서 OutOfMemoryError 예외가 처음 네 번 발생할 때 heapdump.phd와 javacore.txt가 생성된다.
      데이터를 더욱 많이 수집하기 위해 OutOfMemoryError 예외가 발생했을 때 다음과 같이 힙 덤프 대신 시스템 덤프를 생성할 수도 있다.
      -Xdump:heap:none -Xdump:java+system:events=systhrow,
      filter=java/lang/OutOfMemoryError,range=1..4,request=exclusive+compact+prepwalk

      대부분의 애플리케이션에서는 NullPointerException과 같은 예외가 다양한 코드에서 일반적으로 생성된다. 이 때문에 중요한 특정 NullPointerException 예외가 발생하는 시점에서 덤프를 생성하기는 어렵다. 덤프를 생성하는 예외 상황을 더 구체적으로 지정할 수 있도록 throw 및 catch 메소드를 각각 지정하여 "throw" 및 "catch" 이벤트를 처리할 수 있는 특별한 필터링 레벨이 제공된다. # 구분자를 추가한 후, throw 또는 catch 메소드를 적절하게 추가하여 이러한 작업을 수행한다. 예를 들면, 이 옵션은 다음과 같이 bad() 메소드에서 NullPointerException이 throw 명령으로 처리될 때 시스템 덤프가 생성된다.
      -Xdump:system:events=throw,
      filter=java/lang/NullPointerException#com/ibm/example/Example.bad

      이 옵션은 catch() 메소드에서 NullPointerException이 catch 명령으로 처리될 때 시스템 덤프를 생성한다.
      -Xdump:system:events=catch,
      filter=java/lang/NullPointerException#com/ibm/example/Example.catch

      이벤트를 필터링하는 것 외에 덤프가 생성되기를 원하는 이벤트의 범위를 지정할 수도 있다. 예를 들면, 이 옵션은 NullPointerException이 네 번째 발생하는 시점에서만 덤프를 생성한다.
      -Xdump:system:events=throw, filter=java/lang/NullPointerException,range=5

      이 옵션은 NullPointerException 예외가 두 번째, 세 번째, 네 번째 발생할 때만 덤프를 생성한다.
      -Xdump:system:events=throw, filter=java/lang/NullPointerException,range=2..4

      표 2에는 가장 유용한 이벤트와 필터가 요약되어 있다.

      표 2. 사용 가능한 덤프 이벤트

      이벤트 설명 사용 가능한 필터링 예제
      gpf 일반적인 보호 결함(파손) -Xdump:system:events=gpf
      user 사용자가 생성한 신호(SIGQUIT 또는 Ctrl+Break) -Xdump:system:events=user
      vmstop VM 종료(System.exit() 메소드를 호출하는 경우 포함) 종료 코드 -Xdump:system:events=vmstop,filter=#0..#10
      010 사이의 종료 코드를 사용하여 VM 종료 시, 시스템 덤프 생성
      load 클래스 로드 클래스 이름 -Xdump:system:events=load,filter=com/ibm/example/Example
      com.ibm.example.Example 클래스가 로드될 때, 시스템 덤프 생성
      unload 클래스 로드 해제 클래스 이름 -Xdump:system:events=unload,filter=com/ibm/example/Example
      com.ibm.example.Example 클래스가 로드 해제될 때, 시스템 덤프 생성
      throw throw 명령으로 처리된 예외 Exception 클래스 이름 -Xdump:system:events=throw,filter=java/net/ConnectException
      ConnectException이 생성될 때, 시스템 덤프 생성
      catch catch 명령으로 처리된 예외 Exception 클래스 이름 -Xdump:system:events=catch,filter=java/net/ConnectException
      ConnectException이 catch될 때 시스템 덤프 생성
      systhrow Java 예외는 JVM에서 throw된다. (JVM 내부에서 오류 조건이 발견된 경우에만 트리거된다는 점에서 이 예외는 throw 이벤트와 다르다.) Exception 클래스 이름 -Xdump:system:events=systhrow,filter=java/lang/OutOfMemoryError
      OutOfMemoryError가 생성될 때, 시스템 덤프 생성
      allocation Java 오브젝트가 할당됨 할당된 오브젝트의 크기 -Xdump:system:events=allocate,filter=#5m
      5MB를 초과하는 오브젝트가 할당될 때, 시스템 덤프 생성

    • IBM 추적 엔진 사용: 이 추적 엔진을 사용하면 메소드 항목에서 PHD와 시스템 덤프를 트리거하거나 애플리케이션에서 실행 중인 Java 메소드를 종료할 수 있다. IBM 추적 엔진을 제어하는 -Xtrace 명령행 옵션에 trigger 키워드를 사용하여 이러한 조작을 수행할 수 있다. 트리거 옵션을 처리하는 구문은 다음과 같다.
      method{methods[,entryAction[,exitAction[,delayCount[,matchcount]]]]}

      애플리케이션에 다음 명령행 옵션을 추가하면 Example.trigger() 메소드가 호출될 때 시스템 덤프가 생성된다.
      -Xtrace:maximal=mt,trigger=method{com/ibm/example/Example.trigger,sysdump}

      이 명령행 옵션은 Example.trigger() 메소드가 호출될 때 PHD 덤프를 생성한다.
      -Xtrace:maximal=mt,trigger=method{com/ibm/example/Example.trigger,heapdump}

      그렇지만, 메소드가 호출될 때마다 덤프가 생성되는 것을 막기 위해 범위를 설정하는 것이 좋다. 다음 예제는 Example.trigger()가 처음 다섯 번 호출될 때까지는 덤프를 생성하지 않고 여섯 번째 호출될 때, 덤프를 하나 생성한다.
      -Xtrace:maximal=mt,trigger=method{com/ibm/example/Example.trigger,sysdump,,5,1}

      여기에서는 메소드 항목에서만 덤프를 트리거하므로 이 예제에서는 exitAction에 빈 항목을 사용했다.
  • 프로그램 방식: IBM 런타임도 javaDump(), heapDump()systemDump() 메소드가 있는 com.ibm.jvm.Dump 클래스를 제공한다. 이러한 메소드는 각각 스레드 덤프, PHD 덤프 및 시스템 덤프를 생성한다.
Memory Analyzer를 사용하여 덤프 얻기
Memory Analyzer는 덤프를 얻는 데 필요한 메소드(런타임 자체에서 제공하는) 뿐만 아니라 그림 1과 같은 Heap Dump 옵션을 제공한다. 이 옵션을 이용하면 Memory Analyzer와 같은 시스템에서 실행 중인 Java의 스냅샷 덤프를 트리거하여 로드할 수 있다.

그림 1. Memory Analyzer에서 Acquire Heap Dump 기능 사용
Memory Analyzer의 Acquire Heap Dump 기능이 표시된 스크린샷
HotSpot 기반 런타임에서는 Memory Analyzer가 jmap을 사용하여 덤프를 생성한다. IBM 런타임에서는 Java "late attach" 기능과 프로그램 방식 API를 사용하여 덤프를 생성한다. 이전 릴리스에는 "late attach" 기능이 포함되어 있지 않기 때문에 이 기능을 작동하려면 Java 6 SR6가 필요하다.
후처리 요구사항
IBM 시스템 덤프의 경우에는 JDK와 함께 제공되는 jextract 도구를 사용하여 덤프를 후처리해야 한다.
jextract core

사실상, jextract는 덤프를 생성한 시스템과 동일한 실제 시스템에서 덤프를 생성할 때 사용한 JDK와 동일한 JDK 설치판의 jextractjava 프로세스와 함께 실행 중인 라이브러리와 동일한 라이브러리를 읽을 수 있는 액세스 권한을 사용하여 실행된다. jextract가 덤프를 처리하는 과정에서 상당한 CPU 주기를 소비할 수 있다는 점을 감안하면 일부 프로덕션 시스템에서는 이렇게 하는 것이 바람직하지 않을 수 있다. 이런 경우에는 전처리 테스트 시스템과 같은 근사 일치 시스템에서 덤프를 처리해야 한다. Java 런타임의 SR(Service Refresh)과 FP(Fix Pack) 버전이 일치해야 한다.
jextract는 원래의 코어 덤프, 덤프를 처리한 결과물, Java 실행 파일 및 java 프로세스에서 사용한 라이브러리가 포함된 ZIP 파일을 생성한다. jextract를 실행한 후에는 압축되지 않은 원래의 코어 덤프를 삭제할 수 있다. ZIP 파일은 Memory Analyzer로 로드해야 할 파일이다.
이 ZIP 파일을 jdmpview로 로드한 후, heapdump 명령(참고자료 참조)을 실행하여, jextract로 처리한 시스템 덤프에서 PHD 덤프를 추출할 수 있다.

Memory Analyzer를 사용하여 문제점 분석
Memory Analyzer는 메모리가 손실되거나 사용 가능한 메모리에 비해 풋프린트 요구사항이 너무 큰 애플리케이션 영역을 찾는 과정을 통해 OutOfMemoryError를 진단할 수 있다. Memory Analyzer는 메모리 손실을 자동으로 감지하여 메모리 손실 가능성(Leak Suspects) 보고서를 생성한다(참고자료 참조).
HPROF 및 IBM 시스템 덤프에서 사용 가능한 추가 데이터, 특히 필드 이름과 필드 값을 이용하면 메모리 손실 문제를 비롯하여 보다 광범위한 문제점 유형을 진단할 수 있다. 예를 들면, 콜렉션의 저장 공간과 로드 요인을 확인하여 콜렉션의 크기가 효과적인지 확인하거나 ConnectException과 연관된 호스트 이름과 포트를 조사하여 애플리케이션에서 어떤 연결을 생성하려고 했는지 확인할 수 있다.
Inspector를 사용하여 오브젝트의 필드 조사
Memory Analyzer에서 오브젝트를 선택하면 Inspector 뷰에 클래스 계층 구조, 속성 및 정적 데이터를 포함하여 오브젝트와 관련된 사용 가능한 정보가 표시된다. Attributes 패널에는 오브젝트와 연관된 값과 인스턴스 필드가 표시되며 Statics 패널에는 클래스와 연관된 값과 정적 필드가 표시된다.
그림 2에는 간단한 java.net.URL 오브젝트를 Inspector 뷰로 조사한 결과가 표시되어 있으며, 여기에서 해당 URL에서 사용하는 프로토콜 유형과 대상을 비롯한 오브젝트에 관한 세부사항을 확인할 수 있다.

그림 2. Inspector 뷰의 Statics, Attributes 및 Class Hierarchy 패널
Inspector 뷰의 세 가지 패널이 표시된 스크린샷
그림 2의 Attributes 패널에서 URL 오브젝트가 로컬 파일 시스템(경로와 파일 필드에서 지정한 위치)에 있는 JAR 파일(프로토콜 필드)을 참조한다는 사실을 확인할 수 있다.
OQL을 사용하여 오브젝트를 대상으로 쿼리 실행
SQL과 같은 사용자 정의 쿼리를 사용하여 덤프를 쿼리하기 위해 OQL을 사용할 수 있다. 이 주제는 그 자체로 하나의 기사가 될 수 있으므로 여기에서는 몇 가지 예제만 강조한다. 자세한 내용은 Memory Analyzer 내에 있는 OQL 도움말 컨텐츠를 참조한다.
OQL은 외부 참조 경로와 특정 필드에 대하여 오브젝트 세트의 필드를 추적하는 데 유용하다. 예를 들어, 클래스 A에는 유형이 B인 필드 foo가 있고 클래스 B에는 유형이 String인 필드 bar가 있는 경우, 유형이 String인 모든 필드를 찾으려면 다음과 같이 쿼리하면 된다.
SELECT aliasA.foo.bar.toString()
FROM A aliasA

여기에서는 클래스 A에 별명 aliasA를 지정한 후, SELECT 절에서 이 클래스를 참조한다. 이 쿼리는 클래스 A의 인스턴스에서만 정확히 선택한다. 클래스 A의 모든 인스턴스와 서브클래스에서 선택하려면 다음과 같이 한다.
SELECT aliasA.foo.bar.toString()
FROM INSTANCEOF A aliasA

다음은 DirectByteBuffer를 사용한 더욱 복잡한 예제이다.
SELECT k, k.capacity
FROM java.nio.DirectByteBuffer k
WHERE ((k.viewedBuffer=null)and(inbounds(k).length>1))

이 경우에는 해당 오브젝트에서 유지되는 원시 메모리를 제공하는 DirectByteBuffer의 capacity 필드를 가져온다. viewedBuffer 필드가 널이고(이러한 필드는 단지 다른 DirectByteBuffer의 뷰이므로), 인바운드 참조가 둘 이상인 모든 DirectByteBuffer를 필터링할 수도 있다(보류 중인 정리 작업을 팬텀 참조를 사용하여 조사하지 못하도록, 즉 "실시간" DirectByteBuffer만 조사할 수 있도록).
뷰 또는 덤프 간 비교 실행
Memory Analyzer에서는 쿼리를 통해 생성한 테이블을 서로 비교할 수 있다. 이러한 테이블은 같은 덤프에서 생성되거나 서로 다른 덤프에서 생성될 수 있으며, 전자의 경우에는 한 뷰의 String 오브젝트가 다른 뷰에 표시된 콜렉션 오브젝트에 나타나는지 확인할 수 있고, 후자의 경우에는 데이터의 변경사항(예: 오브젝트 콜렉션의 증가)을 확인할 수 있다.
비교를 실행하려면 Compare Basket에 관련 테이블을 추가한 후, Compare Basket에 있는 항목을 비교하도록 요청한다. 먼저, Navigation History에서 해당 테이블 항목을 찾아서 선택한 다음, 그림 3에 표시된 것과 같은 컨텍스트 메뉴에서 Add to Compare Basket을 선택한다.

그림 3. Navigation History 뷰에 있는 테이블을 Compare Basket에 추가
Memory Analyzer의 'Add to Compare Basket' 기능이 표시된 스크린샷
일단 Compare Basket에 항목이 두 개가 있으면 그림 4에서와 같이 이 패널의 오른쪽 맨 위 모서리에 있는 Compare-the-results 단추(빨간색 느낌표)를 사용하여 비교를 실행할 수 있다.

그림 4. Compare Basket에 있는 항목의 결과 비교
Memory Analyzer의 '결과 비교' 기능이 표시된 스크린샷

풋프린트 및 메모리 효율성
Memory Analyzer의 또 다른 중요한 기능은 메모리 손실이 발생되지 않는 상황에서도, 힙의 대부분을 사용 중인 컴포넌트를 찾을 수 있는 기능이다. 메모리 사용량이 감소하면 시스템 용량이나 성능이 개선되고 따라서 가비지를 수집하는 데 소요되는 시간이 줄어 들고 세션을 더 많이 열 수 있게 된다.
먼저 Top Components 보고서를 생성해야 한다. 이 보고서에서는 시스템에 있는 컴포넌트별로 메모리 사용량을 분류하고 각 컴포넌트의 메모리 사용량을 분석하여 낭비되고 있는 메모리를 찾아낸다. 다른 오브젝트에 의해 유지되는 오브젝트는 도미네이터(dominator)가 소유하고 있다고 할 수 있다. Top Components 보고서에는 다른 오브젝트에 의해 소유되지 않은 모든 오브젝트가 표시된다. 이러한 오브젝트를 힙의 최상위 도미네이터라고 한다. 최상위 도미네이터는 오브젝트 클래스를 사용하는 클래스 로더에 의해 분리되며 이러한 모든 최상위 도미네이터와 이 도미네이터가 소유한 오브젝트는 해당 클래스 로더에 할당된다. 이 보고서에서 클래스 로더 중 하나를 선택하고 특정 클래스 로더에 해당하는 새로운 컴포넌트 보고서를 열어서 추가 분석을 수행할 수 있다.
각 컴포넌트에서 콜렉션 오브젝트가 분석된다. java.util.*에서 표시된 바와 같이 Collections 클래스 덕택에 프로그래머는 시간을 많이 절약할 수 있으며 이 클래스에는 제대로 테스트된 목록, 설정 및 맵이 구현되어 있다. 일반적으로 애플리케이션에는 콜렉션이 수백만 개가 있기 때문에 콜렉션에서 낭비되는 공간이 상당하다.
일반적으로 빈 콜렉션으로 인해 메모리가 낭비된다. ArrayList, Vector, HashMapHashSet는 10개의 항목으로 구성된 배열을 유지할 수 있는 기본 크기로 작성되어 항목을 유지할 준비를 한다. 오브젝트가 저장되지 않은 콜렉션을 작성하는 것이 애플리케이션에서는 매우 일반적이다. 이렇게 하면 메모리를 신속하게 소비된다. 예를 들어, 빈 콜렉션 10만 개가 있는 경우에는 이 콜렉션을 유지하는 배열에서만 100,000 * (24+10*4)바이트 = 6MB가 소비될 수 있다.
Empty Collection 보고서는 표준 콜렉션 클래스와 확장을 조사하여 콜렉션의 크기를 분석한다. 그런 다음, 콜렉션의 크기로 정렬된 각 콜렉션의 테이블을 생성한다. (가장 빈번하게 사용된 크기 순으로 정렬된다.) 콜렉션 유형의 인스턴스 대부분이 빈 경우, 이 보고서는 이 인스턴스에 메모리가 낭비될 가능성이 있다는 플래그를 지정한다.
한 가지 해결책은 항목을 삽입할 때까지 콜렉션을 할당하지 않는 것이다. 또 다른 해결책은 기본 크기가 0 또는 1인 콜렉션을 할당한 후, 필요한 경우에 런타임 비용을 일부 치르고 크기를 늘리는 것이다. 세 번째는 초기화 단계가 완료되고 나서 콜렉션 크기를 조정하는 것이다.
관련된 영역은 몇 개의 항목만 있어 많은 공간이 낭비되고 있는 콜렉션이다. Collection Fill Ratio 섹션에는 특정한 비율로 채워진 콜렉션의 인스턴스 수가 각 콜렉션 유형에 따라 표시된다. 이 과정에서 빈 공간이 많은 콜렉션을 확인할 수 있다.
문자열 중복
문자열과 문자 배열은 일반적인 비즈니스 애플리케이션에서 많은 공간을 차지하는 영역으로 분석할 만한 가치가 있다. 컴포넌트 보고서의 이 섹션에서는 일반적인 컨텐츠의 문자열을 분석한다. 문자열은 변경되지 않는다. 동일한 인스턴스를 사용하도록 VM 스펙을 설정하면 문자열 상수의 값이 동일해진다. 동적으로 빌드되는 문자열은 이렇게 되지 않는다. 예를 들어, 값이 동일한 데이터베이스나 디스크에서 데이터를 읽어서 생성한 문자열 두 개는 각각 별도의 인스턴스와 유지 문자 배열로 처리된다. 이러한 문자열을 계속 유지하면 심각한 문제를 초래할 수 있다.
String.intern() 메소드를 사용하거나 사용자 해시 설정 또는 해시맵을 유지하여 이러한 문제점을 해결할 수 있다.
낭비되는 char 배열
String.substring() 메소드는 원래의 문자 배열을 공유하는 새 문자열을 Java 언어로 빌드하여 구현된다. 이러한 방법은 원래의 문자열이 여전히 필요한 경우에는 효과적이다. 그렇지만 문자 배열을 전부 유지하기 때문에 작은 서브스트링만 필요한 경우에는 공간을 일부 낭비하게 된다. Waste In Char Arrays 쿼리를 실행하면 문자열로만 참조되는 문자 배열의 낭비되는 공간의 용량이 표시된다.

Eclipse 번들 및 클래스 로더 계층 구조
최신 애플리케이션은 컴포넌트로 분리되지만, 때로는 애플리케이션의 부분이 클래스 로더를 기반으로 분리되는 경우도 있다. 컴포넌트 클래스 로더 하나를 사용 중지하고 새 클래스 로더를 사용하는 새로운 컴포넌트를 로드하여 컴포넌트를 업데이트할 수 있다. 애플리케이션에 클래스나 오브젝트 또는 클래스 로더에 대한 외부 참조가 없다고 가정하면 결국 이전 버전은 가비지 콜렉션에 의해 해제된다.
Class Loader Explorer 쿼리를 실행하면 시스템에 있는 모든 클래스 로더(모든 애플리케이션을 대상으로 작동하는)가 표시된다. 그리고 클래스 로딩의 문제점을 이해할 수 있도록, 클래스 로더가 로드한 클래스와 클래스 로더의 상위 체인이 표시된다. 이 결과를 조사하면 클래스 로더 사본이 여러 개 존재하는지 여부를 확인할 수 있다. 클래스 로더에 의해 정의된 클래스 인스턴스가 거의 없는 경우에는 클래스 로더가 유휴 상태에 있을 가능성이 있다.
Duplicate Classes 쿼리를 실행하면 여러 가지 클래스 로더에서 로드한 클래스의 이름이 표시된다. 이 결과를 조사하면 클래스 로더로 인한 메모리 손실을 확인할 수 있다. 클래스 로더로 인한 메모리 손실의 경우에는 시스템의 레지스트리와 같은 곳에서 유지되는 오브젝트를 한 번만 참조하면 문제점을 확인할 수 있다. 이 오브젝트는 오브젝트가 속한 클래스, 클래스 로더의 클래스 및 정의된 모든 클래스의 클래스 로더를 유지한다.
일반적으로 사용하는 클래스 로딩 프레임워크는 OSGi 프레임워크이다. 이러한 프레임워크 중 하나는 Eclipse Equinox로, 이 프레임워크는 Eclipse 기반 애플리케이션에서 플러그인을 분리하기 위해 사용될 뿐만 아니라 WebSphere® Application Server 6.1 이상에서도 사용된다. 애플리케이션의 상태를 이해하려면 모든 번들의 상태를 알아야 한다. 그림 5에 표시된 Eclipse Equinox Bundle Explorer 쿼리는 다음과 같은 작업을 수행한다.

그림 5. Eclipse Bundle Explorer
Eclipse Bundle Explorer 뷰가 표시된 스크린샷
시스템이나 HPROF 덤프에는 모든 오브젝트와 필드가 들어 있다. Eclipse Bundle Explorer에는 시스템에 있는 모든 번들과 이 번들의 상태 및 의존성, 종속자 및 서비스가 모두 함께 표시된다. 또한, 예상치 않게 활성화되어 있고 따라서 더 많은 자원을 사용하고 있는 번들도 표시된다.

스레드 데이터 사용량
표 1에 표시된 바와 같이 덤프에는 덤프가 생성된 시점에 수행되고 있던 작업의 고유한 정보를 담고 있는 스레드 세부사항이 포함되어 있다. 이 스레드 세부사항에는 모든 활성 스레드 스택과 각 스레드의 모든 프레임 및 이러한 프레임상의 활성 Java 로컬(가장 중요함)의 일부 또는 전부가 포함되어 있다.
Thread Overview 뷰
그림 6에 표시되어 있는 Thread Overview 뷰에는 JVM의 모든 스레드뿐만 아니라 스레드의 유지 힙 크기, 컨텍스트 클래스 로더, 우선순위, 상태 및 원시 ID와 같은 스레드의 다양한 속성이 표시되어 있다.

그림 6. Thread Overview
Thread Overview 뷰가 표시된 스크린샷
유지 힙 크기는 OutOfMemoryError 상황에서 Java 힙 문제점이 발생하지 않는 경우에 특히 유용하지만, 스레드의 유지 힙 크기를 모두 합하면 용량이 "너무 크다". 이런 경우에는 JVM의 크기가 작고, 스레드 풀의 크기가 너무 크거나 스레드의 평균 또는 최대 Java 힙 "로드"가 너무 크다.
Thread Stacks 뷰
그림 7에 표시되어 있는 Thread Stacks 뷰에는 모든 스레드와 스레드의 스택, 스택 프레임 및 이러한 스택 프레임상의 Java 로컬이 표시되어 있다.

그림 7. Thread Stacks 뷰
Thread Stacks 뷰가 표시된 스크린샷

Thread Details 뷰

Thread Overview 및 Thread Stacks 뷰에서 스레드를 마우스 오른쪽 단추로 클릭한 후, 이 메뉴의 맨 위에 있는 Thread Details를 선택하거나 Java Basics > Thread Details를 차례로 선택한다. 그러면 이 뷰에 원시 스택(사용 가능한 경우)과 같은 자세한 정보가 표시되어 있다.
그림 7에 있는 예제에는 이름이 main(단순한 명령행 프로그램의 기본 스레드)인 java.lang.Thread 유형의 스레드가 확장되어 있다. 스레드의 각 스택 프레임이 표시되어 있으며 사용 가능한 Java 로컬이 있는 스레드가 확장 가능하다. 이 경우에는 StringPlay.method1에서 Play.method2로 인수로 전달되었으며 문자열 user1의 컨텐츠가 빨간색 원으로 강조되어 있다. 덤프를 생성한 시점에 수행 중이었던 작업을 각 스레드 스택 프레임에서 일어난 현상과 관련 오브젝트를 기반으로 재구성하거나 리버스 엔지니어링할 수 있다고 예상할 수 있다.
런타임 최적화로 인해, 메소드 매개변수나 오브젝트 인스턴스와 같은 관련 오브젝트(그렇지만, 이러한 오브젝트는 덤프 안에 있음)가 모두 사용 가능한 것은 아니지만, 능동적으로 "작동"되고 있는 오브젝트는 일반적으로 사용 가능하다.

예외 분석
애플리케이션에서 예외가 발생하면 더 복잡해지기 때문에 예외의 원인을 분석하기가 더욱 어려워진다. 이와 관련된 두 가지 예제는 다음과 같다.
  • 로깅 메커니즘을 사용하면 예외가 손실되거나 예외 메시지가 제거된다.
  • 예외가 발생했지만 불충분한 정보가 있는 메시지가 생성되고 있다.
첫 번째 경우에는 예외 메시지나 전체 예외가 완전히 손실되어 문제점이 존재하는지 여부를 파악하거나 이와 관련된 기본적인 정보를 얻기가 어렵다. 두 번째 경우에는 예외가 로그되었고 예외 메시지와 스택 추적이 사용 가능하지만, 이 메시지에 예외의 원인을 파악하는 데 필요한 정보가 들어 있지 않다.
Memory Analyzer는 오브젝트 안에 있는 필드에 액세스할 수 있는 권한이 있어서 예외 오브젝트에서 예외 메시지를 찾을 수 있다. 어떤 경우에는 원래의 예외에 포함되지 않은 추가 데이터를 추출할 수도 있다.
스냅샷 덤프에서 예외 찾기
스냅샷 덤프에 존재하는 예외를 찾을 수 있는 한 가지 방법은 Memory Analyzer의 OQL 기능을 사용하여 덤프에서 중요한 오브젝트를 찾아내는 것이다. 예를 들어, 다음 쿼리를 실행하면 모든 예외 오브젝트를 찾을 수 있다.
SELECT * 
FROM INSTANCEOF java.lang.Exception exceptions

다음 쿼리를 실행하여 모든 예외로 구성된 목록을 생성한 다음, Inspector 뷰를 사용하여 각 예외 안에 있는 필드를 조사할 수 있다. 예외 메시지가 포함된 필드가 detailMessage 필드라는 것을 알게 되면 쿼리를 수정하여 예외 메시지를 직접 추출하고 이 메시지를 결과 테이블의 일부로 바로 표시할 수도 있다.
SELECT exceptions.@displayName, exceptions.detailMessage.toString() 
FROM INSTANCEOF java.lang.Exception exceptions

앞에 있는 쿼리를 실행하면 그림 8과 같은 결과물이 생성된다.

그림 8. 예외에 대한 OQL 쿼리의 결과물(예외 메시지 포함)
OQL 쿼리의 결과물이 표시된 스크린샷
그림 8에는 애플리케이션에 여전히 존재하는 모든 예외와 throw 명령을 사용하여 예외를 처리했을 때 표시되는 메시지가 있다.
예외와 관련된 추가 정보 추출
덤프에서 예외 오브젝트를 찾으면 예외 메시지를 복구할 수 있다고 하더라도 때로는 예외 메시지가 너무 일반적이거나 모호하여 문제점의 원인을 파악하기 어려운 경우가 있다. java.net.ConnectException은 이에 대한 좋은 예이다. 연결이 허용되지 않은 호스트에 소켓을 연결하려고 시도하면 다음과 같은 메시지가 표시된다.
java.net.ConnectException: Connection refused: connect
at java.net.PlainSocketImpl.socketConnect(Native Method)
at java.net.PlainSocketImpl.doConnect(PlainSocketImpl.java:352)
at java.net.PlainSocketImpl.connectToAddress(PlainSocketImpl.java:214)
at java.net.PlainSocketImpl.connect(PlainSocketImpl.java:201)
at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:377)

at java.net.Socket.connect(Socket.java:530)
at java.net.Socket.connect(Socket.java:480)
at java.net.Socket.(Socket.java:377)
at java.net.Socket.(Socket.java:220)

소켓을 생성하는 코드에 액세스할 수 있는 권한이 있고 사용 중인 호스트 이름과 포트를 이 코드에서 확인할 수 있는 경우에는 이 메시지만 있으면 충분하다. 그러나 호스트 이름과 포트 값을 외부 소스(사용자 입력 값, 데이터베이스 등)에서 가져오기 때문에 호스트 이름과 포트 값이 변경되기 쉬운 더 복잡한 코드에서는 이 메시지가 연결이 거부되는 이유를 파악하는 데 도움이 되지 않는다.
스택을 추적할 때는 유용한 데이터가 들어 있는 소켓 오브젝트를 포함시켜야 하며 Memory Analyzer를 사용하여 스냅샷 덤프에서 소켓 오브젝트를 찾을 수 있는 경우에는 연결을 거부한 호스트 이름과 포트를 찾을 수 있다.
이러한 작업을 처리할 수 있는 가장 손쉬운 방법은 throw 명령을 사용하여 예외를 처리할 때 덤프를 생성하는 것이다. 이 작업은 IBM 런타임에서 다음 -Xdump 옵션 세트를 사용하여 수행할 수 있다.
-Xdump:system:events=throw,range=1..1,
filter=java/net/ConnectException#java/net/PlainSocketImpl.socketConnect

이 옵션을 사용하면 PlainSocketImpl.socketConnect() 메소드에서 ConnectException이 처음 생성될 때 IBM 시스템 덤프가 생성된다.
생성된 스냅샷 덤프를 Memory Analyzer로 로드한 후, Open Query Browser > Java Basics > Thread Stacks 옵션을 사용하여 스레드 스택을 추적함으로써 각 메소드와 연관된 스레드와 오브젝트를 표시할 수 있다.
현재의 스레드와 스레드의 메소드 프레임을 확장하여 이러한 메소드와 연관된 오브젝트를 조사할 수 있다. java.net.ConnectException의 경우에는 가장 중요한 메소드가 java.net.Socket.connect()이다. 이 메소드 프레임을 확장하면 메모리 안에 있는 java.net.Socket 오브젝트에 대한 참조가 표시된다. 이 오브젝트는 앞서 수행하려고 했던 소켓 연결이다.
Socket 오브젝트를 선택하면 그림 9에서 볼 수 있듯이 해당 필드가 Inspector 뷰에 표시된다.

그림 9. Socket 오브젝트를 선택한 경우의 Inspector 뷰
Socket 오브젝트를 선택했을 때의 Inspector 뷰가 표시된 스크린샷
Socket을 실제로 구현한 것은 impl 필드에 있기 때문에 그림 9에 있는 정보는 별로 유용하지 않다. Socket 오브젝트를 확장하거나 기본 패널에서 impl java.net.SocksSocketImpl 행을 선택하여, 또는 Inspector 뷰에서 impl 필드를 마우스 오른쪽 단추로 클릭한 후 Go Into를 선택하여 impl 오브젝트의 컨텐츠를 조사할 수 있다. 그러면 그림 10과 같이 Inspector 뷰에 SocksSocketImpl 필드가 표시된다.

그림 10. SocksSocketImpl 오브젝트에 대한 Inspector 뷰
Socket Impl 오브젝트에 대한 Inspector 뷰가 표시된 스크린샷
그림 10에 표시된 뷰에서 addressport 필드를 확인할 수 있다. 이 경우에는 port 필드는 100이지만 address 필드는 java.net.Inet4Address 오브젝트를 가리키고 있다. 그림 11에 표시된 결과에 있는 Inet4Address 오브젝트의 필드를 조사하려면 동일한 프로세스를 수행한다.

그림 11. Inet4Address 오브젝트에 대한 Inspector 뷰
Inet4Address 오브젝트에 대한 Inspector 뷰가 표시된 스크린샷
hostNamebaileyt60p로 설정된 것을 확인할 수 있다.

팁 및 트릭
유용한 몇 가지 팁과 트릭은 다음과 같다.
  • Memory Analyzer로 인해 메모리 부족 현상이 발생할 수 있다는 점을 기억한다. Eclipse MAT의 경우에는 MemoryAnalyzer.ini 파일에서 -Xmx를 편집한다. ISA 버전에서는 ISA Install/rcp/eclipse/plugins/com.ibm.rcp.j2se.../jvm.properties 파일을 편집한다.
  • Memory Analyzer 32비트 버전에서 계속해서 메모리 부족 현상이 발생하는 경우에는 Eclipse MAT 64비트 버전을 사용하거나 헤드리스 모드(headless mode)를 시도한다(참고자료 참조). (현재 ISA 도구는 64비트가 지원되지 않는다.)
  • Memory Analyzer는 덤프 디렉토리에 "스왑" 파일을 작성하여 덤프를 다시 로드하는 데 걸리는 시간을 절약한다. 이러한 파일은 압축할 수 있으며 다른 시스템으로 전송할 수 있고, 덤프와 같은 디렉토리에 저장할 수도 있으며 이러한 파일을 이용하면 덤프를 완전히 다시 로드할 필요가 없다.
  • 덤프를 생성했을 때, 덤프의 크기가 가비지 콜렉터와 관련이 없는 경우에는 Overview 탭의 Unreachable Objects Histogram 링크를 참조한다. 수명이 긴 콜렉션이 일정 시간 동안 실행되지 않은 경우에는 Java 힙에 Memory Analyzer에서 제거한 가비지가 많이 있을 수 있다.
  • 오브젝트 AB는 서로 직접 참조하지 않지만, 이 두 오브젝트가 오브젝트 C의 일부 세트를 외부 참조하는 경우에는 C 세트의 유지 힙이 A 또는 B의 유지 세트 중 어느 한쪽에 포함되지 않고 오히려 AB의 도미네이터의 유지 세트에 포함된다. 어떤 경우에는 B가 사실상 A의 하위 오브젝트인 C 세트를 일시적으로 유지하고 있을 수도 있으며 이런 경우에는 A를 마우스 오른쪽 단추로 클릭한 후, Java Basics > Customized Retained Set를 선택하여 B의 주소를 제외(-x) 매개변수로 사용할 수 있다.
  • 한 번에 덤프를 여러 개 로드하여 비교할 수 있다. 최근에 생성된 덤프의 히스토그램을 열고 맨 위에 있는 Compare 단추를 클릭한 다음, 기본 덤프를 선택한다.
  • 참조는 직접 또는 간접적으로 "상위" 참조를 다시 참조할 수 있으므로 참조 트리를 탐색할 때는 탐색 루프나 주기를 입력할 수 있다는 사실에 유의한다(예: 링크된 목록에서). 오브젝트 주소에 유의한다. 또한, 오브젝트의 클래스 이름 앞에 단어 class가 있는 경우에는 이 클래스의 정적 인스턴스를 탐색하고 있는 것이다.
  • 대부분의 뷰에 표시되는 String 값은 1,024개 문자로 제한된다. String이 모두 필요한 경우에는 해당 오브젝트를 마우스 오른쪽 단추로 클릭한 후, Copy > Save value to file을 선택한다.
  • 데이터를 내보내어 공유를 하거나 추가로 변환할 수 있도록 대부분의 뷰에는 내보내기 옵션이 있고 대부분의 HTML 결과는 파일 시스템에서 작성된다. 또한, 그리드에서 행을 선택하고 Ctrl+C를 눌러서 텍스트 형식으로 표현된 행을 클립보드로 복사할 수 있다.

결론
Eclipse.org에 기술되어 있듯이 원래 Memory Analyzer는 "메모리 손실을 파악하고 메모리의 소비를 줄이는 데 도움이 되는 빠르고 기능이 다양한 Java 힙 분석기"로 개발되었다. 그러나 Memory Analyzer의 기능은 Eclipse.org에 기술되어 있는 기능을 훨씬 능가한다. "보통"의 메모리 문제점을 진단하는 역할 이외에도 스냅샷 덤프는 추적 및 패칭(patching)과 같은 다른 유형의 문제점 판별 기술에 대한 대안으로 사용될 수 있다. 특히, Memory Analyzer에서 HPROF 덤프와 IBM 시스템 덤프를 사용하면 원래의 소스 코드에서 원시 및 필드 이름과 같은 메모리 컨텐츠를 확인할 수 있다. 이 기사에서 다룬 다양한 뷰를 사용하면 전체 풋프린트 및 메모리 효율성, Eclipse 번들 및 클래스 로더 관계, 스레드 데이터 사용량, 스택 프레임 로컬 및 예외 등과 같은 문제점을 즉시 탐색하거나 리버스 엔지니어링할 수 있다. 또한, OQL과 Memory Analyzer 플러그인 모델을 이용하면 일반적인 분석을 자동화할 수 있는 프로그램 방식의 메소드와 쿼리 언어를 사용하여 더 쉽게 덤프를 조사할 수 있다.

참고자료
교육

댓글 없음:

댓글 쓰기