2015-08-20

JAVA Thread 와 unable to create new native thread



상황

리눅스에서 java로 만든 multi thread 프로그램을 동작 시키고 있는데, java.lang.OutOfMemoryError: unable to create new native thread 가 발생.
JVM 이 죽는다.


Java Thread  종류

1. 데몬 스레드(Daemon Thread)
데몬 스레드는 다른 비데몬 스레드가 없다면 동작을 중지한다.
가비지 컬렉션 같은 것들이다.

2. 비데몬 스레드(Non-daemon Thread)
보통 class에서 실행하는 main은 비데몬 스레드이다.
main같은 비데몬 스레드가 일반적으로 Stack 을 보면 thread in VM 으로 표현되고
VM Thread 라고 한다.
비슷하게 일반 로직이 아닌 JVM 의 native 기능을 사용하는 thread를 Thread In Native 라고 하며 Native Thread 라고 한다.
일반적으로 socket, rmi관련 thread를 들수 있다.


원인

크게 두가지 원인으로 나눌수 있다.
1. 리눅스에서 MAX thread 개수를 넘어서 Thread를 생성 하려 할때.
2. OS 에서 Thread 생성에 필요한 메모리를 실제로 할당해주지 못할때.

위 두가지 상황 모드 정상인 상황은 아니다.

Linux MAX thread 수 확인 법
하여간에  일반적으로 java thread는 linux의 ps 명령등으로 확인이 불가능하다.
즉 개별 프로세스로 보이지도 않고 커널 쓰레드도 아니다.
확인 하려면 시스템 설정을 조회해야 한다.




조회방법
cat /proc/sys/kernel/threads-max
설정 방법 echo 1000 > /proc/sys/kernel/threads-max

* 실제로 1000 개하면 몇만개 이상 되어야 한다.


프로세스당 Thread 수 확인법

조회방법
ps -eLo pid,cmd,nlwp

결과
PID CMD                         NLWP
    1 /sbin/init                     1
    2 [kthreadd]                     1
    3 [migration/0]                  1
58651 /usr/java/jdk1.8.0_05/bin/j  144

여기 결과값 NLWP가 number of light weight process의 약자로 java thread 의 수이다.
커널 쓰레드도 1로 표시된다.
위는 jdk의 프로그램이 144개의 쓰레드를 생성 했다는 의미이다.


java 에서성 할수 있는 프로세스 확인

public class test
{
   public static void main(String[] args)
    {
        int cnt = 0;
        while(true){
            cnt++;
                System.out.println("cnt:" + cnt);
            new Thread(new Runnable(){
                public void run() {
                    try {
                        Thread.sleep(10000000);
                    } catch(InterruptedException e) { e.printStackTrace();}    
                }
            }).start();
        }
    }
}


위 프로그램 을 실제 동작 시키면  플래폼에 따라 생성 개수의 차이가 발생한다.
32bit JVM 의 경우 약 9000개 64jvm의 경우 약 34000개 정도 까지 무난히 생성된다.

이는 JVM 프로세스가 관리하는 스택 저장 공간의 사이즈와 연결되는데
java 실행시 -Xss 옵션으로 스택의 사이즈를 지정하면 된다.
(-Xss128k) 옵션을 너무 작게 주면 최소 값 얼마 이상 주라고나오는데 32bit는 100k 64bit는 160k 이다. 기본값은 128k 라고 한다.


따라서 리눅스에서 max thread 생성 개수가 남아 있더라도 ,
stack 에 의해서 thread 의 생성에 java는 제한을 가지게 된다.



해결
java.lang.OutOfMemoryError: unable to create new native thread가 발생하면
위에 쭉 언급한 바와 같이 실제 메모리 문제라기 보다는 쓰레드의 생성 개수 제한 떄문이 가능서이 조금더 높다.


1. ulimit -a  명령으로 프로세스당 메모리 사용제한 양을 확인 하고 조치 한다.
2. 리눅스의 max thread 수를 늘린다.
3. java thread stack size 크기를 줄인다.
4. 실제 물리 메모리를 늘린다.
5. 사실은 제일 먼저 엄한 Thread를 생성하고 있지는 않은지  확인 한다.

등으로 조치한다.

참고
heap 메모리의 부족과는 상관없다.
이 에러는 java 메모리의 Stack 메모리 부분에서 발생한다.


No comments:

Post a Comment