728x90

OutOfMemory란?
Garbage Collector가 새로운 Object를 유지 하기 위해 충분한 메모리 공간을 확보하지 못할 때 발생.
Vendor사의 JVM 메모리 모델이 다르기 때문에 사용하는 JVM 메모리 모델을 인지하고 있어야 한다.
  ex) HPUX는 Heap에 Perm이 포함되어 있음.
   IBM 은 Heap과 Perm이 별도 산정.

OOM 유형별 현상 및 조치방법
 1. Heap Memory가 Full인 경우
  1.1 응용프로그램에서의 과도한 사용
   발생하는 시점의 Heap dump, Thread dump가 필요
   여기서 중요한 점은 OOM으로 인해 프로세스가 죽기 전인 해당 현상이 발생하고 있는 시점에서 떠야한다.
   특히 Thread dump는 생성할 당시의 스레드 상태만 알 수 있기 때문에 3초간격으로 3회를 추천.
   그래야 오래 수행되는 특정 스레드를 찾을 수 있기 때문 (3개의 Thread Dump에서 동일하게 수행되고 있는 스레드가 문제일 확률이 높음)
   생성한 Heap dump는 MemoryAnalyzer를 통해 분석
   MemoryAnalyzer에서 StackTrace까지 확인 가능하기에 제대로 된 Heap dump만 있어도 Thread dump는 필요 없다.

  1.2 leak에 의해 점차적으로 쌓이는 경우
   gc log 및 jtstat을 통해 해당 현상의 추이를 확인 할 수 있다.
   추이를 확인하여 메모리 사용률이 높은 지점을 포착하여 Heap dump 생성 후 MemoryAnalyzer를 통해 분석

 2. Perm이 Full인 경우
  Perm 영역은 Class loader에 의해 load되는 Class, Method 등에 대한 Meta 정보가 저장되는 영역이다.
  Code가 올라가는 부분이기 때문에 Code가 모두 Load되고 나면 거의 일정한 수치를 유지한다.
  특히 어플리케이션 디플로이/리디플로이시에 많이 겪을 수 있다.
  따라서 모니터링을 통해 적정한 수치까지 Perm size를 증가 시켜주어야 한다.

 3. C Heap(Native)이 문제인 경우
  3.1 Maxdsiz 
   Maxdsiz란 proccess의 data 세그먼트의 최대 사이즈를 의미하는 HPUX의 커널파라매터 이다.(default 값은 64MB)
   Heap에는 java heap과 c heap으로 나뉘는데 C heap은 jdk내부적으로 C라이브러리를 사용하거나 jni를 통해서 c프로그램을 호출할 시 Data 영역을 사용하게 된다.
   Maxdsiz 문제로 OOM을 마주하게 되었을 때의 조치사항
    1) Maxdsiz 는 최대값인 4G(0xfffff000)로 설정하고, 실행유저의 ulimit의 Data값을 따로 설정하지 말것.
      Maxdsiz는 limit을 지정하는 값이기 때문에, 최대값(4G)으로 설정하여도 아무런 부작용이 없다.
    2) java_q4p를 사용하는 것.(Heap size를 2G 이상 설정하면 자동으로 java_q4p로 실행)
※${JAVA_HOME}/bin/IA64N/java_q4p 로 실행하면 강제적으로 가능
       Maxdsiz로 최대값(4G)을 줘도,  Xmx 500M 로 사용중이라면, java_q2p 까지만 data영역으로 쓸수 있기 때문에, 2G까지 제한 됨.
    3) Glance를 통해 Data 영역 모니터링 방법
      glance 실행 → Shift + m 입력 → jvm PID 입력

  3.2 JAVA C heap small block arena corruption 
   C heap에서 메모리 주소를 침범하여 발생하는 메모리 corruption이 발생할 때(HPUX), _M_SBA_OPTS 옵션을 사용하여 해결 할 수 있다.

    메모리 corruption의 대표 예
    char *p = malloc (10); 
    char *name = (char *) malloc(11);      
    memcpy ( p,name,11); // Problem begins here 

   p는 10 bytes, name은 11 bytes  인데 p에 11bytes를 쓰면, 뒤에 1byte 에 memory corruption이 발생. 이걸 실행시에는 crash가 발생하지 않음. Compile도 문제없이 됨.
   그 1byte는 free list ptr값의 일부였는데 훼손이 된 상태로 있다가 해당 free list ptr값을 가지고 malloc을 하려고 했을때 뭔가 문제가 있다는 걸 감지하여 crash를 내며 죽음.
   Corruption이 언제 일어났는지 알수 없고, app에서 corruption code를 찾기 어렵다면, 편법으로 memory allocation마다 padding을 붙여서 corruption이 일어나는 것에 쿠션장치를 둘수 있으나,
   얼마의 padding이 적절한지는 crash가 안날 때까지 계속 고쳐나가면서 _M_SBA_OPTS 의 적정값을 찾아야 하고 padding만큼 app의 메모리 사용량은 증가하는 side effect가 있으며, 성능도 느려질 수 있다고 한다.

   환경 변수 _M_SBA_OPTS 설정은 두가지 목적으로 적용 및 사용하게 된다.
    1) small block allocator 를 사용하는 주 목적은 성능 개선
     molloc() 요청시 한번에 할당하는 개수를 지정할 수 있어, 할당 시 지정 값 만큼 한번에 할당되어 다음번 molloc() 요청시 미리 할당된 미사용 block을 사용하기 때문에 성능이 개선됨.
    2) C heap에서 corruption이 있을 때
     block 할당 단위를 요구량에 맞추는 것이 아니라 요구량 이상으로 (여기서는 100바이트 단위로) 할당을 하면, 오류로 인해 주소 범위가 조금 벗어나도 할당 범위 안에 있다면 문제를 일으키지 않음.

   환경변수 _M_SBA_OPTS=A:B:C 각 값의 의미 
    Default 값 _M_SBA_OPTS=512:100:16시 맨 앞 512 값보다 작은 값에 적용이란 뜻으로 맨 앞의 값보다 적은 값까지 SBA(small block allocator) 할당이 적용.
        가운데 100값은 한번에 할당 하는 개수를 의미
     마지막 16값은 malloc시 할당 되는 값의 단위
    그래서 Default 값 _M_SBA_OPTS=512:100:16시 malloc(10)을 요청하게 되면 16byte 100개 가 할당되며, 또 다시 malloc(10) 요청이 오면 기존에 16byte 100개 할당되었던 block중 미사용 block을 사용하게 되며, 만일 미사용 block이 없으면 다시 16bite 100개가 할당됨.
    Malloc()이 Malloc(16)byte가 넘게 되면 각 malloc값이 맞춰어 16,32,48,64,80….512까지 맞춰서 100개씩 할당되며 같은 값의 malloc시 할당되었던 block중 미사용 block을 사용하게 되며 만일 미사용 block이 없으면 다시 같은 크기의 byte로 100개 가 할당됨.

   결론적으로 _M_SBA_OPTS 옵션을 사용하여 메모리 corruption이 발생하지 않도록 padding값을 주되, 적정한 값은 설정 후 모니터링을 통해 찾아야 함.

728x90

+ Recent posts