IT_Programming/Java

[펌] IBM JVM 에서 Memory Leak의 발견과 대처

JJun ™ 2011. 6. 22. 14:15

----------------------------------------------------------------------------------

 출처: http://blog.naver.com/hyperhit/90033370638

----------------------------------------------------------------------------------

 

제목 : IBM JVM에서 Memory Leak 발견과 대처

작성자 : 자바스터디 네트워크 조대협

작성일 : 2005-01-26

 

 

Memory Leak이란, Java Application에서 객체 사용을 위해서 메모리를 할당한 후에,

메모리를 회수 하지 못하고 잔여 객체들이 메모리 상에 남아 있어서 가용 가능한 메모리 양이

줄어들어 결과적으로 Out Of Memory 에러를 발생시키다가 서비스가 불가능한 상태가 되는 현상을

이야기한다. 

 

<그림 1. Memory Leak 발생할때의 GC Graph 상황 >

 

일반적으로 Memory Leak 발생할 경우 Memory 사용 상황을 모니터링할 있는 GC로그를 보면

<그림 1.> 같은 형태를 띠게 됨으로 GC Graph 통해서 증상을 확인할 있다.

 

 

Memory Leak 문제 해결의 절차는 <그림2> 같이 이루어 진다.

먼저 Memory Leak 있는 증상을 발견하면 Profiling 통해서 Memory Leak 발생하는

Point 발견하고 Application 문제일경우에는 해당 Application 수정하며, WAS 문제일

경우에 해당 상황에 대한 자료를 수집하여 Memory Leak 해결하는 패치를 제작하여

적용하게 된다.

 

< 그림 2. Memory Leak 해결 절차 >

 

일반적으로 Leak 원인을 발견하는 과정은 Jprobe등의 Profiling Tool 사용해야 하나

IBM JVM 경우 순간의 Memory 사용량을 있는 Heap Dump 기능을 제공하기 때문에

이를 이용하면 Memory Leak 현상을 발견할 있다.

 

 

< 그림 3.Memory Leak 분석을 위한 Heap Dump 수집 시점 >

 

Heap Dump 추출하기 위해서는 먼저 운영후 초기(start하자 마자가 아니라 어느 정도 운영이

된후) Heap Dump 수집하고(Heap Dump1), Out Of Memory 나오기전에 메모리 증가가

커졌을때 Heap Dump 수집해서 (Heap Dump2) 변화된 내용을 분석하여 Leak 되는

Object 판별한다.

 

 

 

IBM에서 Heap Dump 수집과 분석

 

1) Heap dump 수집

     IBM에서 Heap Dump 받기 위해서는 환경 변수에 아래 내용을 추가한다.

 

  export IBM_HEAPDUMP=true
  export IBM_HEAP_DUMP=true
  export IBM_HEAPDUMP_OUTOFMEMORY=true
  export IBM_JAVADUMP_OUTOFMEMORY=true

 

그 후, heap dump 받으려는 시점에 kill ?3 pid 해주면 heapdump.xxx라는 이름으로

heap dump 파일이 생성된다.

 

 

2) Heap dump 분석

     먼저 Heap Dump 직접 보기가 어렵기 때문에 분석할 있는 도구를 받을 필요가 있는데,

     http://alphaworks.ibm.com/tech/heaproots에서 분석 도구를 다운받아서 설치하고

 

     % java ?jar xxxx/HR205.jar heapdump 파일명 입력한다.

 

프롬프트에서 os 1-5 입력하면 현재 메모리를 가장 많이 차지하고 있는 상위 5개의 Object 들을

보여준다.

 

> os 1-5

 

Showing all objects, sorted by size.

 

Addr       Size       Name

-------------------------------------------------------------------------------

0x6ff6fc00 393,232    array of java/util/Hashtable$Entry

0x6349c690 329,224    primitive array

0x45690988 106,888    primitive array

0x52674568 99,808     primitive array

0x3db30ba0 98,824     primitive array

 

Displayed results  : 1-5

Matched objects    : 12,707,289 / 12,707,289

Total Size         : 748,100,472 / 748,100,472

 

 

os 각각의 객체 사이즈가 큰것부터 sorting 하는것이고, ot 전체 객체 사이즈

    (referencing하고 있는) 순서부터 출력을 한다.

 

다음 i 명령어를 입력하고 address입력부분에 위에서 메모리를 많이 차지하고 있는 Object

주소를 입력하면 Object 대한 정보를 보여주고, Object Reference하고 있는 Parents

Object 보여준다. 다시 i 명령을 입력해서 상위 Object 찾아가다보면 실제로 어디서 Leak

나왔는지를 찾을 있다.

 

Enter: o{a,s,t,d,m,n}, g{c,s}, t{c,s,n}, i, p, d{t,d,m} or help for more info

> i

 

Enter 0x<addr> for object to show info on [0x6ff6fc00]

> 0x6ff6fc00

Enter range of lines to print in format 'M','L-U','-U' or 'L-' [1-20]

> 1-10

 

Name : array of java/util/Hashtable$Entry

 

REFERENCES TO / PARENTS of 0x6ff6fc00

 

Addr       Size       Refs  Name

-------------------------------------------------------------------------------

0x39d4be18 48         1     java/util/Hashtable

 

 


 

상위 Object 정보

REFERENCES FROM / CHILDREN of 0x6ff6fc00

 

 

Addr       Size       Refs  Name

-------------------------------------------------------------------------------

0x4d30e898 32         3     java/util/Hashtable$Entry

0x4caa5698 32         2     java/util/Hashtable$Entry

0x4db95a58 32         2     java/util/Hashtable$Entry

0x51e243c8 32         2     java/util/Hashtable$Entry

0x6a64c5a8 32         2     java/util/Hashtable$Entry

0x4d1f24f0 32         2     java/util/Hashtable$Entry

0x60e444f0 32         2     java/util/Hashtable$Entry

0x4f7976b8 32         3     java/util/Hashtable$Entry

0x60eeba08 32         2     java/util/Hashtable$Entry

 

Displayed results : 1-10

Total refs        : 43,196

Parents, Children : 1 , 43,195

Root Type         : N

Root-Owner        : 0x30354018

Parent-Owner      : 0x39d4be18

Total size        : 643,815,432

Descendants       : (Check setup with '? p' and then 'p' to re-process.)

Max Depth         : (Check setup with '? p' and then 'p' to re-process.)

Size              : 393,232 / 748,100,472

 

다른 방법으로는 prompt에서 d 입력하면 Memory 얼마 이상 점유하고 있는

object들의 stack trace 추출할 있다.

 

Enter total-size threshold [1048576] ß 얼마 이상 크기의 Object들을 볼지 입력한.(Default는 1M)
>
Enter max depth or -ve for unlimited [8] ß Stack의 depth를 지정한다. (Default 8)
>
Enter 0x<addr> to dump from one address or any value for all roots [-]
>
Dumping object(s)  : 5605 roots, sorted by total-size
Filter             : total-size >= 1,048,576 and depth at most 8
Prune              : N
 
<0> [128,341,248] 0x009c1a40 [64] com/sybase/jdbc2/jdbc/SybSQLWarning
<1>   [128,340,984] 0x009c2250 [64] com/sybase/jdbc2/jdbc/SybSQLWarning
<2>     [128,340,384] 0x009c25a0 [64] com/sybase/jdbc2/jdbc/SybSQLWarning
<3>       [128,339,752] 0x009c2dc8 [64] com/sybase/jdbc2/jdbc/SybSQLWarning
<4>         [128,339,120] 0x009f58a0 [64] com/sybase/jdbc2/jdbc/SybSQLWarning
<5>           [128,338,504] 0x00a3e5f0 [64] com/sybase/jdbc2/jdbc/SybSQLWarning
<6>             [128,337,888] 0x00a48fe0 [64] com/sybase/jdbc2/jdbc/SybSQLWarning
<7>               [128,337,248] 0x00a539d8 [64] com/sybase/jdbc2/jdbc/SybSQLWarning
<8>                 [128,336,632] 0x00a58b68 [64] com/sybase/jdbc2/jdbc/SybSQLWarning
                      - 6 children of 0x00a58b68 too deep.
                    - 5 children of 0x00a539d8 filtered.
                  - 5 children of 0x00a48fe0 filtered.
                - 5 children of 0x00a3e5f0 filtered.
              - 5 children of 0x009f58a0 filtered.
            - 5 children of 0x009c2dc8 filtered.
          - 5 children of 0x009c25a0 filtered.
        - 5 children of 0x009c2250 filtered.
      - 5 children of 0x009c1a40 filtered.
 
1/5605 roots were dumped. There were 9 objects expanded.

 

 

위에서 부터 root node이고 표현방식은 다음과 같다.

 

<Node depth> [ 객체가 referencing하고 이는 메모리 크기] 주소 [현재 Object 자체 크기] class

 

정보를 통해서 어느 부분에서 메모리를 많이 차지하고 있는지를 trace 있다.

 
○ 위에서 설명한 HeapRoot는 Text기반 툴이기 때문에, Tree형태의 메모리 구조를 탐색하기가 
쉽지가 않다.
그래서 HeapRoot의 GUI버전인 HeapAnalyzer라는 툴이 있는데
http://alphaworks.ibm.com/tech/heapanalyzer 에서 다운받아서 설치할 수 있다.
 
HeapAnalyzer를 이용해서 Memory Leak을 분석해서 Analysis의 Treeview를 보면 
다음과 같은 정보를 얻을 수 있다.

 

먼저 root stack에서 부터 하나하나 child node를 탐색하다보면 객체가 가지고 있는 
total memory 사용량이 점차적으로 감소하고 있음을 확인할 수 있다. <그림에서 1) 부분 >
그림에서 2) 부분에 보면 메모리 할당량이 420M에서 갑자기 319M로 급격히 떨어짐을 볼 수 있는데,
나머지 약 100M의 객체들이 모두 java.util.HashMap$Entry 객체들로 모두 일정하게 33k,27k의 용량을
가진
객체들로 판단할 수 있고, 이런 객체들이 모여서 100M정도의 메모리를 소요하고 있음을 볼 수 있다.
<그림에서 3) >

이 HashMap객체들이 어떤 내용을 가지고 있는지 Tree를 열어보면 JMSConnection 객체들을
가지고 있음을 볼수 있고, 결론적으로 이는 JMSConnection 객체 관련 모듈의 Memory Leak 현상으로 판단할 수 있다.


'IT_Programming > Java' 카테고리의 다른 글

Java 에서의 Object Pool 기법  (0) 2011.07.04
Java Real-time Heap Dump 생성  (0) 2011.06.22
wait & notify & notifyAll 동작 과정  (0) 2011.06.13
Java Security Manager & Java policy 파일 생성  (0) 2011.06.10
GC Dump 보기  (0) 2011.05.19