Ошибка памяти Java: невозможно создать новый собственный поток - PullRequest
25 голосов
/ 20 ноября 2011

Я получаю эту ошибку на моем сервере UNIX при запуске моего сервера Java:

Exception in thread "Thread-0" java.lang.OutOfMemoryError: unable to create new native thread
at java.lang.Thread.start0(Native Method)
at java.lang.Thread.start(Thread.java:640)
at [... where ever I launch a new Thread ...]

Это происходит каждый раз, когда у меня работает около 600 потоков.

Я установил эту переменную на сервере:

$> ulimit -s 128

Что выглядит странным для меня, так это результат этой команды, которую я выполнил, когда ошибка произошла в последний раз:

$> free -m
              total       used       free     shared    buffers     cached
Mem:          2048        338       1709          0          0          0
-/+ buffers/cache:        338       1709
Swap:            0          0          0

Я запускаю свой Java-сервер так:

$> /usr/bin/java -server -Xss128k -Xmx500m -jar /path/to/myJar.jar

Моя версия Debian:

$> cat /etc/debian_version
5.0.8

Моя версия Java:

$> java -version
java version "1.6.0_26"
Java(TM) SE Runtime Environment (build 1.6.0_26-b03)
Java HotSpot(TM) 64-Bit Server VM (build 20.1-b02, mixed mode)

Мой вопрос: я прочитал в Интернете, что моя программа должна обрабатывать что-то вроде 5000 потоков или около того. Так что же происходит и как исправить пожалуйста?


Редактировать: это вывод ulimit -a при открытии оболочки:

core file size          (blocks, -c) unlimited
data seg size           (kbytes, -d) unlimited
scheduling priority             (-e) 0
file size               (blocks, -f) unlimited
pending signals                 (-i) 794624
max locked memory       (kbytes, -l) 32
max memory size         (kbytes, -m) unlimited
open files                      (-n) 100000
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) 794624
virtual memory          (kbytes, -v) unlimited
file locks                      (-x) unlimited

Я запускаю скрипт как демон из init.d, и вот что я запускаю:

DAEMON=/usr/bin/java
DAEMON_ARGS="-server -Xss128k -Xmx1024m -jar /path/to/myJar.jar"
ulimit -s 128 && ulimit -n 10240 && start-stop-daemon -b --start --quiet --chuid $USER -m -p $PIDFILE --exec $DAEMON -- $DAEMON_ARGS \
    || return 2

Edit2: я столкнулся с этим вопросом переполнения стека с помощью java-теста для потоков: how-many-threads-can-a-java-vm-support

    public class DieLikeADog { 
        private static Object s = new Object(); 
        private static int count = 0; 
        public static void main(String[] argv){ 
            for(;;){ 
                new Thread(new Runnable(){ 
                        public void run(){ 
                            synchronized(s){ 
                                count += 1; 
                                System.err.println("New thread #"+count); 
                            } 
                            for(;;){ 
                                try { 
                                    Thread.sleep(100); 
                                } catch (Exception e){ 
                                    System.err.println(e); 
                                } 
                            } 
                        } 
                    }).start(); 
            } 
        } 
    } 

На моем сервере программа вылетает после 613 потоков. Теперь я уверен, что это не нормально, а связано только с конфигурацией моего сервера. Может кто-нибудь помочь, пожалуйста?


Редактировать 3: Я сталкивался с этой статьей и многими другими, объясняя, что linux не может создать 1000 потоков , но вы, ребята, говорите мне, что вы можете сделать это в своих системах. Я не понимаю.

Я также запустил этот скрипт на своем сервере: threads_limits.c , а ограничение составляет около 620 потоков.

Мой веб-сайт сейчас недоступен, и это худшее, что могло случиться с моим проектом. Я не знаю, как перекомпилировать glibc и все такое. Это слишком много работы имо.

Полагаю, мне следует перейти на сервер Windows. Поскольку ни одна из настроек, предложенных на этой странице, не внесла никаких изменений: ограничение в моей системе составляет от 600 до 620 потоков, независимо от того, какая программа задействована.

Ответы [ 6 ]

12 голосов
/ 22 ноября 2011

Только что получил следующую информацию: Это ограничение, наложенное моим хост-провайдером. Это не имеет ничего общего с программированием или Linux.

7 голосов
/ 20 ноября 2011

Базовая операционная система (в данном случае Debian Linux) не позволяет процессу создавать больше потоков.Посмотрите здесь, как увеличить максимальное количество: Максимальное количество потоков на процесс в Linux?

Я прочитал в Интернете, что моя программа должна обрабатывать что-то вроде 5000 потоков или около того.

Это зависит от ограничений, установленных для ОС, количества запущенных процессов и т. Д. При правильных настройках вы можете легко достичь такого количества потоков.Я запускаю Ubuntu на своем собственном компьютере, и я могу создать около 32000 потоков, прежде чем перейти к пределу для одной Java-программы, когда все мои «обычные вещи» работают в фоновом режиме (это было сделано с помощью тестовой программы, которая только что создала потоки, которыепошел спать сразу в бесконечном цикле).Естественно, что большое количество потоков, которые на самом деле что-то делают, вероятно, довольно быстро остановит потребительское оборудование.

3 голосов
/ 20 ноября 2011

Можете ли вы попробовать ту же команду с меньшим размером стека "-Xss64k" и передать результаты?

2 голосов
/ 21 ноября 2011

Я начинаю подозревать, что отсутствует "Native Posix Thread Library".

>getconf GNU_LIBPTHREAD_VERSION

Должно появиться что-то вроде:

NPTL 2.13

Если нет, установка Debian испортилась,Я не уверен, как это исправить, но установка Ubuntu Server кажется хорошим шагом ...

для ulimit -n 100000;(откройте fd: s) следующая программа должна быть способна обрабатывать 32 000 потоков или около того.

Попробуйте:

package test;

import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.concurrent.Semaphore;

public class Test {

    final static Semaphore ss = new Semaphore(0);


    static class TT implements Runnable {

        @Override
        public void run() {
            try {
                Socket t = new Socket("localhost", 47111);
                InputStream is = t.getInputStream();
                for (;;) {
                    is.read();
                }

            } catch (Throwable t) {
                System.err.println(Thread.currentThread().getName() + " : abort");
                t.printStackTrace();
                System.exit(2);
            }

        }
    }

    /**
     * @param args
     */
    public static void main(String[] args) {
        try {

            Thread t = new Thread() {
                public void run() {
                    try {
                        ArrayList<Socket> sockets = new ArrayList<Socket>(50000);
                        ServerSocket s = new ServerSocket(47111,1500);
                        ss.release();

                        for (;;) {
                            Socket t = s.accept();
                            sockets.add(t);
                        }
                    } catch (Exception e) {
                        e.printStackTrace();
                        System.exit(1);

                    }
                }
            };


            t.start();
            ss.acquire();


            for (int i = 0; i < 30000; i++) {

                Thread tt = new Thread(new TT(), "T" + i);
                tt.setDaemon(true);
                tt.start();
                System.out.println(tt.getName());
                try {
                    Thread.sleep(1);
                } catch (InterruptedException e) {
                    return;
                }
            }

            for (;;) {
                System.out.println();
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    return;
                }
            }

        } catch (Throwable t) {
            t.printStackTrace();
        }
    }
}
1 голос
/ 20 ноября 2011

Ваша JVM не может выделить стек или некоторую другую память для каждого потока.Уменьшение размера стека с помощью -Xss поможет увеличить число потоков, которые вы можете создать до появления OOM (но JVM не позволит вам установить сколь угодно малый размер стека).

Вы можете убедиться в этом, увидевкак количество созданных потоков изменяется при настройке -Xss или при запуске strace на вашей виртуальной машине Java (почти наверняка вы увидите mmap(), возвращающий ENOMEM непосредственно перед тем, как возникнет исключение).

Проверьте также свой ulimit на виртуальный размер, то есть ulimit -v.Увеличение этого лимита должно позволить вам создавать больше потоков с одинаковым размером стека.Обратите внимание, что ограничение размера резидентного набора (ulimit -m) неэффективно в текущем ядре Linux .

Кроме того, снижение -Xmx может помочь, оставляя больше памяти для стеков потоков.

0 голосов
/ 20 ноября 2011

Это выходит из памяти.

Также необходимо изменить ulimit. Если ваша ОС не дает вашему приложению достаточно памяти -Xmx, я полагаю, не будет никакой разницы.

Я думаю, что -Xmx500m не имеет никакого эффекта.

Попробуйте

ulimit -m 512m с -Xmx512m

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...