Dag-scheduler-event-loop java.lang.OutOfMemoryError:无法创建新的本机线程

时间:2016-10-29 02:52:22

标签: java apache-spark

运行5-6小时后,我从火花驱动程序中得到以下错误。我使用的是Ubuntu 16.04 LTS和open-jdk-8。

Exception in thread "ForkJoinPool-50-worker-11" Exception in thread "dag-scheduler-event-loop" Exception in thread "ForkJoinPool-50-worker-13" java.lang.OutOfMemoryError: unable to create new native thread
    at java.lang.Thread.start0(Native Method)
    at java.lang.Thread.start(Thread.java:714)
    at scala.concurrent.forkjoin.ForkJoinPool.tryAddWorker(ForkJoinPool.java:1672)
    at scala.concurrent.forkjoin.ForkJoinPool.deregisterWorker(ForkJoinPool.java:1795)
    at scala.concurrent.forkjoin.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:117)
java.lang.OutOfMemoryError: unable to create new native thread
    at java.lang.Thread.start0(Native Method)
    at java.lang.Thread.start(Thread.java:714)
    at scala.concurrent.forkjoin.ForkJoinPool.tryAddWorker(ForkJoinPool.java:1672)
    at scala.concurrent.forkjoin.ForkJoinPool.signalWork(ForkJoinPool.java:1966)
    at scala.concurrent.forkjoin.ForkJoinPool$WorkQueue.push(ForkJoinPool.java:1072)
    at scala.concurrent.forkjoin.ForkJoinTask.fork(ForkJoinTask.java:654)
    at scala.collection.parallel.ForkJoinTasks$WrappedTask$class.start(Tasks.scala:377)
    at scala.collection.parallel.AdaptiveWorkStealingForkJoinTasks$WrappedTask.start(Tasks.scala:443)
    at scala.collection.parallel.AdaptiveWorkStealingTasks$WrappedTask$$anonfun$spawnSubtasks$1.apply(Tasks.scala:189)
    at scala.collection.parallel.AdaptiveWorkStealingTasks$WrappedTask$$anonfun$spawnSubtasks$1.apply(Tasks.scala:186)
    at scala.collection.mutable.ResizableArray$class.foreach(ResizableArray.scala:59)
    at scala.collection.mutable.ArrayBuffer.foreach(ArrayBuffer.scala:48)
    at scala.collection.parallel.AdaptiveWorkStealingTasks$WrappedTask$class.spawnSubtasks(Tasks.scala:186)
    at scala.collection.parallel.AdaptiveWorkStealingForkJoinTasks$WrappedTask.spawnSubtasks(Tasks.scala:443)
    at scala.collection.parallel.AdaptiveWorkStealingTasks$WrappedTask$class.internal(Tasks.scala:157)
    at scala.collection.parallel.AdaptiveWorkStealingForkJoinTasks$WrappedTask.internal(Tasks.scala:443)
    at scala.collection.parallel.AdaptiveWorkStealingTasks$WrappedTask$class.compute(Tasks.scala:149)
    at scala.collection.parallel.AdaptiveWorkStealingForkJoinTasks$WrappedTask.compute(Tasks.scala:443)
    at scala.concurrent.forkjoin.RecursiveAction.exec(RecursiveAction.java:160)
    at scala.concurrent.forkjoin.ForkJoinTask.doExec(ForkJoinTask.java:260)
    at scala.concurrent.forkjoin.ForkJoinTask.doJoin(ForkJoinTask.java:341)
    at scala.concurrent.forkjoin.ForkJoinTask.join(ForkJoinTask.java:673)
    at scala.collection.parallel.ForkJoinTasks$WrappedTask$class.sync(Tasks.scala:378)
    at scala.collection.parallel.AdaptiveWorkStealingForkJoinTasks$WrappedTask.sync(Tasks.scala:443)
    at scala.collection.parallel.ForkJoinTasks$class.executeAndWaitResult(Tasks.scala:426)
    at scala.collection.parallel.ForkJoinTaskSupport.executeAndWaitResult(TaskSupport.scala:56)
    at scala.collection.parallel.ParIterableLike$ResultMapping.leaf(ParIterableLike.scala:958)
    at scala.collection.parallel.Task$$anonfun$tryLeaf$1.apply$mcV$sp(Tasks.scala:49)
    at scala.collection.parallel.Task$$anonfun$tryLeaf$1.apply(Tasks.scala:48)
    at scala.collection.parallel.Task$$anonfun$tryLeaf$1.apply(Tasks.scala:48)
    at scala.collection.parallel.Task$class.tryLeaf(Tasks.scala:51)
    at scala.collection.parallel.ParIterableLike$ResultMapping.tryLeaf(ParIterableLike.scala:953)
    at scala.collection.parallel.AdaptiveWorkStealingTasks$WrappedTask$class.compute(Tasks.scala:152)
    at scala.collection.parallel.AdaptiveWorkStealingForkJoinTasks$WrappedTask.compute(Tasks.scala:443)
    at scala.concurrent.forkjoin.RecursiveAction.exec(RecursiveAction.java:160)
    at scala.concurrent.forkjoin.ForkJoinTask.doExec(ForkJoinTask.java:260)
    at scala.concurrent.forkjoin.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:1339)
    at scala.concurrent.forkjoin.ForkJoinPool.runWorker(ForkJoinPool.java:1979)
    at scala.concurrent.forkjoin.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:107)
java.lang.OutOfMemoryError: unable to create new native thread
    at java.lang.Thread.start0(Native Method)
    at java.lang.Thread.start(Thread.java:714)
    at scala.concurrent.forkjoin.ForkJoinPool.tryAddWorker(ForkJoinPool.java:1672)
    at scala.concurrent.forkjoin.ForkJoinPool.deregisterWorker(ForkJoinPool.java:1795)
    at scala.concurrent.forkjoin.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:117)

这是默认情况下在客户端模式下运行的Spark Driver程序产生的错误,所以有些人说只是通过传递--driver-memory 3g标志来增加堆大小,但是消息"unable to create new native thread"确实如此说JVM要求操作系统创建一个新线程,但操作系统不能再分配它,JVM可以通过请求操作系统创建的线程数量取决于平台,但通常是64位操作系统上的32K线程。 JVM。

当我做ulimit时 - 我得到以下

core file size          (blocks, -c) 0
data seg size           (kbytes, -d) unlimited
scheduling priority             (-e) 0
file size               (blocks, -f) unlimited
pending signals                 (-i) 120242
max locked memory       (kbytes, -l) 64
max memory size         (kbytes, -m) unlimited
open files                      (-n) 1024
pipe size            (512 bytes, -p) 8
POSIX message queues     (bytes, -q) 819200
real-time priority              (-r) 0
stack size              (kbytes, -s) 8192
cpu time               (seconds, -t) unlimited
max user processes              (-u) 120242
virtual memory          (kbytes, -v) unlimited
file locks                      (-x) unlimited

cat / proc / sys / kernel / pid_max

32768

cat / proc / sys / kernel / threads-max

240484

“无法创建新的本机线程”显然意味着它与堆无关。所以我认为这更像是一个操作系统问题。

3 个答案:

答案 0 :(得分:5)

在Spark 2.0.0中使用ForkJoinPool似乎存在一个错误,即创建了太多线程。特别是在您在Dstream上调用窗口操作时使用的UnionRDD.scala中。

https://issues.apache.org/jira/browse/SPARK-17396所以根据此票据我升级到2.0.1并解决了问题。

答案 1 :(得分:0)

根本原因分析:

JVM中的线程需要一些肘部空间来执行他们被召唤处理的工作。当内存空间超过内存空间时,我们已经为问题建立了基础: enter image description here 消息java.lang.OutOfMemoryError: Unable to create new native thread表示 Java应用程序已达到可以启动的线程数的限制

是什么造成的?

每当JVM从操作系统请求新线程时,您都有机会面对java.lang.OutOfMemoryError: Unable to create new native thread。只要底层操作系统无法分配新的本机线程,就会抛出此OutOfMemoryErro r。本机线程的确切限制非常依赖于平台,因此我们建议通过运行类似于以下示例的测试来找出这些限制。但是,一般来说,造成java.lang.OutOfMemoryError的情况:无法创建新的本机线程会经历以下阶段:

  1. JVM内部运行的应用程序请求新的Java线程
  2. JVM本机代码代理创建操作系统的新本机线程的请求
  3. 操作系统尝试创建一个新的本机线程,该线程需要将内存分配给线程
  4. 操作系统将拒绝本机内存分配,因为32位Java进程大小耗尽了其内存地址空间 - 例如(2-4)GB流程大小限制已被命中 - 或者OS的虚拟内存已完全耗尽
  5. java.lang.OutOfMemoryError:无法创建新的本机线程错误。
  6. 举个例子

    以下示例在循环中创建并启动新线程。运行代码时,会快速达到操作系统限制并显示java.lang.OutOfMemoryError: Unable to create new native thread消息。

    while(true){
        new Thread(new Runnable(){
            public void run() {
                try {
                    Thread.sleep(10000000);
                } catch(InterruptedException e) { }        
            }    
        }).start();
    }
    

    确切的本机线程限制取决于平台,例如Windows,Linux和Mac OS X上的测试显示:

    1. 64位Mac OS X 10.9,Java 1.7.0_45 - JVM在创建#2031个线程后死亡
    2. 64位Ubuntu Linux,Java 1.7.0_45 - JVM在创建#31893线程后死亡
    3. 64位Windows 7,Java 1.7.0_45 - 由于操作系统使用的线程模型不同,此错误似乎不会在此特定平台上引发。在线程#250,000上,该进程仍处于活动状态,即使交换文件已增长到10GB且应用程序面临极端性能问题。 因此,请通过调用一个小测试确定您知道自己的限制,并找出java.lang.OutOfMemoryError:无法创建新的本机线程的时间将被触发
    4. 解决方案是什么?

      有时,您可以通过增加操作系统级别的限制来绕过Unable来创建新的本机线程问题。例如,如果您限制了JVM可以在用户空间中生成的进程数,则应该检出并可能增加限制:

      [root@dev ~]# ulimit -a
      core file size          (blocks, -c) 0
      --- cut for brevity ---
      max user processes              (-u) 1800
      

      通常,OutOfMemoryError触发的新本机线程的限制表示编程错误。当你的应用程序产生数千个线程时,很可能会出现严重错误 - 那里没有很多应用程序可以从如此庞大的线程中受益。 解决问题的一种方法是开始获取线程转储以了解情况。

      资源链接:

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

      这里还有更多其他答案:

      1. How to solve java.lang.OutOfMemoryError: unable to create new native thread
      2. OutOfMemoryError: Unable to Create New Native Thread – Problem Demystified
      3. https://stackoverflow.com/a/16789621/2293534
      4. Java: Unable to create new native thread

答案 2 :(得分:0)

在Java中,你可以偶然发现两种Out of Memory错误:

  1. java.lang.OutOfMemoryError Java heap space error:这个 应用程序尝试时将触发异常 将更多数据分配到堆空间区域,但是还不够 它的空间。虽然可能有足够的内存 你的机器,你已经达到了允许的最大内存量 您的JVM,可以通过-Xmx参数设置
  2. java.lang.OutOfMemoryError: Unable to create new native thread 每当JVM从操作系统请求新线程时就会发生。如果 底层操作系统无法分配新的本机线程,这一点 将抛出OutOfMemoryError。
  3. 1)检查线程系统范围设置

    / proc / sys / kernel / threads-max文件提供了线程数量的系统范围限制。 root用户可以根据需要更改该值:

    $ echo 100000 > /proc/sys/kernel/threads-max
    

    您可以通过/ proc / loadavg文件系统检查当前运行的线程数:

    $ cat /proc/loadavg
    0.41 0.45 0.57 3/749 28174
    

    观看第四场!该字段由两个用斜杠(/)分隔的数字组成。第一个是当前正在执行的内核调度实体(进程,线程)的数量;这将小于或等于CPU的数量。斜杠后面的值是系统上当前存在的内核调度实体的数量。在这种情况下,您正在运行749个线程

    2)检查每个用户的进程数

    在Linux机器上,线程本质上只是具有共享地址空间的进程。因此,您必须检查您的操作系统是否允许您为用户提供足够的进程。这可以通过以下方式检查:

    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) 515005
    max locked memory       (kbytes, -l) 64
    max memory size         (kbytes, -m) unlimited
    open files                      (-n) 4096
    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) 1024
    virtual memory          (kbytes, -v) unlimited
    file locks                      (-x) unlimited
    

    默认情况下,每个用户的默认进程数为1024。此时我们将计算正在运行的进程数。运行的进程数可以用ps输出计算:

    $ ps -elf | wc -l  
    220
    

    但是这个数字不考虑进程可以生成的线程。如果您尝试使用-T运行ps,您将看到所有线程:

    $ ps -elfT | wc -l  
    385
    

    正如您所看到的,由于线程,进程数量显着增加。通常,这绝不是任何类型的问题,但在基于Java的应用程序中,这可能会导致系统遇到系统限制!让我们继续我们的调查。让我们看看你的JBoss Process产生了多少线程。您可以通过至少两种方式完成此任务:

    $ ps -p JBOSSPID -lfT | wc -l
    

    上面的shell将返回为PID指示的进程创建的轻量级进程数。这应该与jstack生成的线程转储计数匹配:

    $ jstack -l JBOSSPID | grep tid | wc -l
    

    现在您应该有证据表明您需要增加用户的进程数。这可以使用以下命令完成:

    $ ulimit -u 4096
    

    3)检查线程PID限制

    一旦你计算了线程数,那么你应该验证你没有达到kernel.pid_max limit参数指定的系统限制。您可以通过执行以下命令来检查此值:

    $ sysctl -a | grep kernel.pid_max  
    
    kernel.pid_max = 32768
    

    4)减少线程堆栈大小

    如果无法修改操作系统设置,可以使用的另一个选项是减小堆栈大小。 JVM有一个有趣的实现,通过它可以为堆分配更多的内存(不一定由堆使用),堆栈中可用的内存越少,并且由于线程是从堆栈生成的,实际上这意味着更多的“内存” “在堆意义上(通常是人们谈论的)会导致更少的线程能够并发运行。

    首先检查默认的线程堆栈大小,该大小取决于您的操作系统:

    $  java -XX:+PrintFlagsFinal -version | grep ThreadStackSize
         intx ThreadStackSize                           = 1024                                {pd product}
    

    如您所见,我们的机器中默认的线程堆栈大小为1024 kb。为了减小堆栈大小,请在JVM选项中添加“-Xss”选项。在JBoss EAP 6 / WildFly中,最小的Thread堆栈大小为228kb。您可以通过更改JAVA_OPTS在独立模式下更改它,如以下示例所示:

    JAVA_OPTS="-Xms128m -Xmx1303m -Xss256k"
    

    在域模式下,您可以在各个级别(主机,服务器组,服务器)配置jvm元素。在那里,您可以设置请求的堆栈大小,如以下部分所示:

    <jvm name="default">
                <heap size="64m" max-size="256m"/>
                <jvm-options>
                    <option value="-server"/>
                    <option value="-Xss256k"/>
                </jvm-options>
    </jvm>
    

    资源链接:

    How to solve java.lang.OutOfMemoryError: unable to create new native thread