[java] “java.lang.OutOfMemoryError : 새 네이티브 스레드를 만들 수 없습니다.”

"java.lang.OutOfMemoryError : unable to create new native Thread32k 스레드 후에 8GB RAM VM 에서 ” 가 발생 합니다 (ps -eLF | grep -c java).

그러나 "top" and "free -m" shows 50% free memory available. JDk는 64 비트이며 HotSpot과 JRockit 모두에서 시도되었습니다. Server에는 Linux 2.6.18이 있습니다.

우리는 또한 OS stack size (ulimit -s)조정 및 최대 프로세스 (ulimit -u) 제한, limit.conf 증가를 시도했지만 모두 헛된 것입니다.

또한 가능한 거의 모든 힙 크기 조합을 시도하여 낮음, 높음 등으로 유지했습니다.

응용 프로그램을 실행하는 데 사용하는 스크립트는

/opt/jrockit-jdk1.6/bin/java -Xms512m -Xmx512m -Xss128k -jar JavaNatSimulator.jar /opt/tools/jnatclients/natSimulator.properties

답장을 보내 주셔서 감사합니다.

/etc/security/limits.conf 및 ulimit 편집을 시도했지만 여전히 동일합니다.

[root@jboss02 ~]# ulimit -a
core file size          (blocks, -c) 0
data seg size           (kbytes, -d) unlimited
scheduling priority             (-e) 0
file size               (blocks, -f) unlimited
pending signals                 (-i) 72192
max locked memory       (kbytes, -l) 32
max memory size         (kbytes, -m) unlimited
open files                      (-n) 65535
pipe size            (512 bytes, -p) 8
POSIX message queues     (bytes, -q) 819200
real-time priority              (-r) 0
stack size              (kbytes, -s) 10240
cpu time               (seconds, -t) unlimited
max user processes              (-u) 72192
virtual memory          (kbytes, -v) unlimited
file locks                      (-x) unlimited



답변

이것은 예외 이름이 강력하게 암시하더라도 메모리 문제가 아니라 운영 체제 리소스 문제입니다. 원시 스레드가 부족합니다. 즉, 운영 체제가 JVM에서 사용할 수있는 스레드 수입니다.

그렇게 많이 필요하지 않기 때문에 이것은 드문 문제입니다. 스레드가 끝나야하지만 끝나지 않는 곳에서 무조건적인 스레드 스폰이 많이 있습니까?

가능하다면 Executor의 제어하에 Callable / Runnables를 사용하여 다시 작성하는 것을 고려할 수 있습니다. 코드에서 쉽게 제어 할 수있는 다양한 동작을 가진 많은 표준 실행기가 있습니다.

(스레드 수가 제한된 이유는 여러 가지가 있지만 운영 체제마다 다릅니다.)


답변

부하 테스트 중에 동일한 문제가 발생했는데 그 이유는 JVM이 새 Java 스레드를 더 이상 만들 수 없기 때문입니다. 아래는 JVM 소스 코드입니다.

if (native_thread->osthread() == NULL) {
// No one should hold a reference to the 'native_thread'.    
    delete native_thread;
if (JvmtiExport::should_post_resource_exhausted()) {
    JvmtiExport::post_resource_exhausted(
        JVMTI_RESOURCE_EXHAUSTED_OOM_ERROR |
        JVMTI_RESOURCE_EXHAUSTED_THREADS,
        "unable to create new native thread");
    } THROW_MSG(vmSymbols::java_lang_OutOfMemoryError(), "unable to create new native thread");
} Thread::start(native_thread);`

근본 원인 : JVMTI_RESOURCE_EXHAUSTED_OOM_ERROR (자원 고갈 (메모리 고갈 의미)) 또는 JVMTI_RESOURCE_EXHAUSTED_THREADS (스레드 고갈) 인 경우 JVM에서이 예외가 발생합니다.

제 경우에는 Jboss가 요청을 처리하기 위해 너무 많은 스레드를 생성하고 있지만 모든 스레드가 차단됩니다. 이로 인해 JVM은 메모리와 함께 스레드와 함께 소모됩니다 (각 스레드는 각 스레드가 차단되기 때문에 해제되지 않는 memory를 보유합니다).

분석 된 자바 스레드 덤프에서 거의 61K 스레드가 우리의 방법 중 하나에 의해 차단되어이 문제를 일으키는 것으로 나타났습니다. 아래는 스레드 덤프 부분입니다.

"SimpleAsyncTaskExecutor-16562" #38070 prio=5 os_prio=0 tid=0x00007f9985440000 nid=0x2ca6 waiting for monitor entry [0x00007f9d58c2d000]
   java.lang.Thread.State: BLOCKED (on object monitor)


답변

OS가 생성하려는 스레드 수를 허용하지 않거나 JVM에서 일부 제한에 도달 할 수 있습니다. 특히 32k와 같은 라운드 수인 경우 한 종류 또는 다른 종류의 제한이 원인 일 가능성이 높습니다.

정말로 32k 스레드가 필요합니까? 대부분의 현대 언어는 재사용 가능한 스레드 풀에 대해 일종의 지원을 제공합니다. Java도 ExecutorService제스퍼 사용자가 언급했듯이. 수동으로 새 풀을 만드는 대신 이러한 풀에서 스레드를 요청할 수 있습니다.


답변

스레드 스택 크기도 살펴보고 더 많은 스레드가 생성되는지 확인하는 것이 좋습니다. JRockit 1.5 / 1.6 의 기본 스레드 스택 크기 는 Linux OS에서 64 비트 VM의 경우 1MB입니다. 32K 스레드는이 요구 사항을 충족하기 위해 상당한 양의 실제 및 가상 메모리가 필요합니다.

시작점으로 스택 크기를 512KB 로 줄이고 애플리케이션에 대한 더 많은 스레드를 만드는 데 도움이되는지 확인하십시오. 또한 수평 적 확장 (예 : 더 많은 물리적 또는 가상 머신으로 애플리케이션 처리 분할)을 탐색하는 것이 좋습니다.

64 비트 VM을 사용할 때 실제 제한은 OS 물리적 및 가상 메모리 가용성과 ulimitc와 같은 OS 튜닝 매개 변수에 따라 달라집니다. 또한 다음 기사를 참조로 권장합니다.

OutOfMemoryError : 새 원시 스레드를 만들 수 없음 – 문제가 설명 됨


답변

jvm이 systemd를 통해 시작되면 일부 Linux OS에서 프로세스 당 maxTasks 제한 (실제로 작업은 스레드를 의미 함)이있을 수 있습니다.

“서비스 상태”를 실행하여이를 확인하고 maxTasks 제한이 있는지 확인할 수 있습니다. 있는 경우 /etc/systemd/system.conf를 편집하고 구성을 추가하여 제거 할 수 있습니다. DefaultTasksMax = infinity


답변

bash에서 top을 사용할 때 표시되지 않는 고스트 프로세스로 인해 동일한 문제가 발생했습니다. 이로 인해 JVM이 더 많은 스레드를 생성하지 못했습니다.

나를 위해 모든 자바 프로세스를 jps ( jps셸에서 실행) 로 나열하고 kill -9 pid각 고스트 프로세스에 대해 bash 명령을 사용하여 개별적으로 죽일 때 해결 되었습니다 .

이것은 일부 시나리오에서 도움이 될 수 있습니다.


답변

java.lang.OutOfMemoryError: Unable to create new native threadJVM이 OS에서 새 스레드를 요청할 때마다 직면 할 수있는 기회가 있습니다. 기본 OS가 새 원시 스레드를 할당 할 수 없을 때마다이 OutOfMemoryError가 발생합니다. 네이티브 스레드의 정확한 제한은 플랫폼에 따라 매우 다르므로 아래 링크 예제와 유사한 테스트를 실행하여 이러한 제한을 알아내는 것이 좋습니다. 그러나 일반적으로 원인 java.lang.OutOfMemoryError: Unable to create new native thread이 되는 상황 은 다음 단계를 거칩니다.

  1. JVM 내에서 실행되는 응용 프로그램에서 새 Java 스레드를 요청합니다.
  2. JVM 네이티브 코드는 OS에 대한 새 네이티브 스레드를 생성하도록 요청을 프록시합니다. OS는 스레드에 메모리를 할당해야하는 새 네이티브 스레드를 생성하려고합니다.
  3. OS는 32 비트 Java 프로세스 크기가 메모리 주소 공간을 고갈 시켰거나 (예 : (2-4) GB 프로세스 크기 제한에 도달 했음) 또는 OS의 가상 메모리가 완전히 고갈 되었기 때문에 기본 메모리 할당을 거부합니다.
  4. java.lang.OutOfMemoryError : 새 원시 스레드를 작성할 수 없음 오류가 발생합니다.

참조 : https://plumbr.eu/outofmemoryerror/unable-to-create-new-native-thread