----------------------------------------------------------------------------------
출처: 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 |
그 후, 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
> 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
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 |