자바에서는 개발자가 프로그램에서 별도로 메모리 관리를 하지 않는다. 이것은 C/C++에서는없던 획기적인 것이었다. 자바의 메모리 관리 개념은  개발자를 열광케 하고, 나아가 자바가 세상을 지배하는 언어가 되는데 핵심 역할을 담당하였다

그러나 애석하게도 자바에서는 여전히 메모리 문제가 발생하고있다. C/C++처럼 빈번하지는 않지만 종종 OutOfMemoryError 발생하고 있으며, 이러한 메모리 부족 에러는 운영자나 개발자가 가장 껄끄러워하는 문제 중에 하나로 인식되어있다.

1.1 자바의 메모리 부족 유형

Out Of Memory Error 발생하는 원인을 보면 크게 (1)단지 메모리가 부족할  (2)Heavy 서비스가 수행되면서 혹은 (3) 메모리 LEAK 의한 메모리 부족 때문으로 구분할  있다.

절대적인 메모리 부족

단지 메모리가 부족하다는 것은  설정된 메모리량이 요구되는 메모리량에 비해 부족하다는 것이다. 프로그램이나 기타 오류가 아닌 단지 값이 적게 설정되었다는 것을 의미하기 때문에 통상적으로는 -Xmx값을 늘려줌으로써 해결되는 것이 보통이다. 실제로는 의외로 JVM 시작시 메모리 옵션을 빠뜨리는 경우가 많다. 혹은 -Xmx256 같이 메모리 단위(원하는 설정-Xmx256m) 빠트리는 경우도 있다.  물론 옵션을 잘못 기술하는 것은 단순한 실수이지만, 자바  메모리에 대한 경험이 전혀 없어서  단위 시간당 서비스 호출건수(Service Arrival Rate) 비해  없이 적은량의 메모리를 지정하는 경우도 종종 있다.

SUN/HP JVM에서는 perm 영역이 작아서 발생하는 경우가 있다. 메모리의 perm영역에는 클래스코드 등이 저장되는 공간으로  사용되는 클래스가 많은 경우에는 사이즈를 늘려 주어야 한다.

Heavy Application Service 의한 부족

OutOfMemoryError  응용서비스(ex Web Request 처리 로직) 순간적으로 메모리를 과도하게사용함으로써 발생할  있다.

데이터 베이스에서 너무 많은 데이터를 로딩하거나 검색 조건이 잘못되어 검색서버에서 너무많은 텍스트를 조회하는 경우가 해당된다.  다른 경우로 과거에 upload/download프로그램에서 자주 발견되던 것으로 byte[] buffer에서 buffer 크기를 너무 크게 설정함으로써 연속공간부족 현상(IBM JVM) 발생하는 경우나,  동시에 여러 개의 요청이 발생하여 단위 시간당 절대사용량이 많아 OuOfMemory발생하는 경우를 생각할  있다. 물론 후자의 경우는 application정상적으로 메모리를 많이 사용하는지 단지 프로그램 오류인지는 판별하기 어려울 수도 있다.

LEAK 의한 메모리 부족

마지막으로 Memory Leak 발생하여 메모리가 부족해지는 경우이다.  보다 정확하게 자바에서메모리 LEAK 로직적으로 사용되지 않는 객체가 GC  없는 strong reference 의해 참조되어 메모리 사용량이 증가하는 상태를 말한다. 대부분 적절한 반환을 거치지 않아 발생한다.

대표적으로 JDBC관련 클래스를 사용하고 close() 호출하지 않게 되어 발생하는 경우를 생각할  있다(물론 JDBC 따라서 혹은 Web Application Server 따라서 메모리 Leak 발생하지 않을   있다.)

메모리 LEAK 다른 사례로 Cache 구현 로직에 문제가 있는 경우이다. CACHE에서 불필요한데이터의 제거 로직이 정상적으로 동작하지 않는 경우 OutOfmemoryError 발생할 수있다.

Http Session에서 데이터가 증가하는 현상 또한  범주에 포함 시킬  있을 것이다.

 

1.2  OutOfMemoryError 발생시 원인 분석

화면이나 프로그램 로그에서 OutOfMemoryError 보게 된다면 어떤 경우에 발생하는지를 정확히 판별해야 한다.

단지 설정이 잘못된 경우라면 통상적으로 JVM startup 혹은 startup이후 짧은 시간내에OutOfMemory 발생하게된다. 따라서 서버를 리스타트   OutOfMemoryError 보게 된다면 옵션 설정을 먼저 의심해 보아야 한다. 그러지만 PERM영역이 부족한 경우에는 약간 시간을두고 발생하게 되지만 특징은 HEAP메모리가 부족하지 않는데 OutOfMemoryError 발생하면서 SUN/HP JVM이라면  PERM영역이 부족하지 않은지를 먼저 확인해야  것이다.

만약 (2)경우라면 어떤 현상이 관찰될까? HEAP MEM 그래프를 보면 갑자기 메모리 사용량이급격히 증가하고 GC 빈번해지는 현상이 관찰되는 것이 일반적이다. 시간에 따라 메모리 사용량이 증가하지 않고 어느 순간에 메모리 사용량이 급격히 증가하고 GC 빈번해 지는 현상이발생한다면 특정 Application 메모리를 과도하게 사용함을 추정할  있다. 다만 Active Service 증가한 이후에 Memory사용량이 증가하고 GC 빈번해지면 인과관계가 약간 불분명할 수는 있다  다른 원인에 의한 Active Service 증가하고  service들이 사용하는 메모리량이 많아서 OutOfmemoryError 발생할 수는 있는데 사실 이런 경우는 빈번하지 않다.

IBM JVM 경우에 HEAP 여유가 충분하고 GC 빈번해지지도 않으면서 갑자기OutOfMemoryError 발생한 경우에는 fragmentation 의한 연속공간부족을 의심할  있다.

마지막으로 메모리 LEAK HEAP그래프가 시간에 따라 증가되는 현상으로 나타난다. 시간이 몇시간인 경우도 있으나  달이 넘는 경우도 있다. 메모리 사용량은 명시적으로System.gc() 호출한  비교해야 한다.

단지 설정이 잘못되거나 너무 적은 메모리를 설정한 경우에는 설정을 수정함으로써 해결하면OK이지만 특정 Application 의한 OutOfmemoryError Memory leak 발생하는 경우에는 해결을 위해 보다 논리적 접근이 필요하다.

특정 application 의한 불특정 시점에 OutOfMemoryError 발생하는 것이 확인된다며 어떤application Memory Error 발생하는지를 찾아야 한다. 만약 해당 Application uploaddownload 관련있는 프로그램이라면 데이터를 제어하기 위한 버퍼 사이즈를 먼저확인하고단순히 DB 사용하는 프로그램이라면 DB Access 데이터 량을 확인하는 것이 먼저이다.

 제니퍼는 OutOfMemoryError 의한 서비스 종료가 발생하면 WARNING 발생하고 에러 정보를 저장함으로 이것을 확인하는것도 방법이다. 통상적으로 메모리를 과도하게 사용한Application 수행되면 순간적으로 해당 인스턴스의 응답시간/CPU사용량등이 증가하게되며XVIEW상에서 모든 프로그램의 응답시간이 급격하게 증가하는 현상을 관찰할 수있는데 이때가장 높은 (응답시간이 길거나/CPU사용량이 높음) 위치하는 것이 문제의 Application 경우가 많다. 따라서 일자별 XView 데이터 조회를 통해서 해당 시간대를 면밀히 관찰하면 쉽게 찾을  있다.

Memory Leak 이것은 원만큼 자바 튜닝이 공력이 붙지 않으면 해결하기 힘들다  시간이 필요한데다가 개발 서버에서는 좀처럼 재연되지 않기 때문에 특히 어렵다. 메모리 릭은 원칙적으로HEAP DUMP 분석하는 것이 가장 빠른 길이다.

과거 JAVA 1.4 에서는 IBM JVM에서만 HEAP DUMP 가능했지만  JAVA1.5이상에서는 모든플렛폼에서 HEAP DUMP 가능하다.

 제니퍼에서는 HEAP 사용량을 모니터링 하고 트랜잭션별 응답시간과 CPU사용량을 모니터링함으로써 메모리 문제 해결에 크게 도움이  수있다.

제니퍼를 통해서 OutOfMemoeyError 어떠한 유형인지를 판별하고 만약 LEAK 의심이 된다면 언제쯤 OutOfMemoryError 발생할지 그리고 그메모리 부족이 서비스 응답시간에 영향은없는지를 모니터링 하여 안정적으로 시스템을 운영하면서 메모리 문제를 해결할  있다.

 



Posted by sjokim
,