2012-05-24 2 views
11

Я читал и тестировал и стучал головой о стену в течение дня из-за этой ошибки.Java `OutOfMemoryError` при создании <100 нитей

У меня есть Java-код в класс под названием Listener, который выглядит, как этот

ExecutorService executor = Executors.newFixedThreadPool(NTHREADS); 
boolean listening = true; 
int count = 0; 
while (listening) { 
    Runnable worker; 
    try { 
     worker = new ServerThread(serverSocket.accept()); // this is line 254 
     executor.execute(worker); 
     count++; 
     logger.info("{} threads started", count); 
    } catch (Exception e1){ 
     //... 
    } 
} 

Я донастроить JVM параметры которой -Xmx (где-то от 1 до 15G) и -Xss (где-то от 104K до 512M). Сервер имеет 24 ГБ ОЗУ, но также должен работать с базой данных, поддерживающей программу.

После создания 2-20 нитей (несколько десятков существуют в другом месте в программе, а), я получаю ошибку

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:657) 
at java.util.concurrent.ThreadPoolExecutor.addWorker(ThreadPoolExecutor.java:943) 
at java.util.concurrent.ThreadPoolExecutor.execute(ThreadPoolExecutor.java:1325) 
at xxx.Listener.run(Listener.java:254) 

$java -version выходы:

java version "1.6.0_24" 
OpenJDK Runtime Environment (IcedTea6 1.11.1) (fedora-65.1.11.1.fc16-x86_64) 
OpenJDK 64-Bit Server VM (build 20.0-b12, mixed mode) 

Там всегда большая количество свободной памяти в системе, когда это происходит, и другие программы продолжают выполнять штраф. Что заставляет Java думать, что у нее больше нет памяти для новых потоков?

UPDATE: Возможно, это больше, чем я думала, мне удалось получить эту ошибку (только один раз), когда я использовал ^C:

OpenJDK 64-Bit Server VM warning: Exception java.lang.OutOfMemoryError occurred dispatching signal SIGINT to handler- the VM may need to be forcibly terminated 

и то же самое произошло, когда я пытался убить клиент (также написанный на Java и работающий на одном сервере, это единственный поток, который читает файл и отправляет его на сервер через сокет), поэтому существует определенная предел за пределами JVM, заставляющий вмешиваться в другой, но я не могу себе представить, что, если у меня все еще есть свободная память и я вообще не использую swap? Сервер -Xmx1G -Xss104k Клиент -Xmx10M

UPDATE2: Бросив PERL Forks::Super библиотеку и запуск клиентов из Баша позволь мне получить до 34 потоков, прежде чем сервер упал с OOME, поэтому запуск нескольких клиентов, безусловно, оказали влияние на сервере, но в то же время я все равно могу запустить более 34 (68, если подсчитывать клиентов) java-потоков за раз. Какие системные ресурсы блокируют создание большего количества потоков (т. Е. Где я должен искать свиней)? Когда все (клиенты, сервер, GC ...) бежит из памяти в то же время, top говорит это о моем CPU и памяти:

Cpu(s): 0.0%us, 0.0%sy, 0.0%ni,100.0%id, 0.0%wa, 0.0%hi, 0.0%si, 0.0%st 
Mem: 24681040k total, 1029420k used, 23651620k free, 30648k buffers 
Swap: 26836988k total,  0k used, 26836988k free, 453620k cached 

Update3: ли в журнал hs_error ниже, показывают, что мой java не 64 бит?

# There is insufficient memory for the Java Runtime Environment to continue. 
# Cannot create GC thread. Out of system resources. 
# Possible reasons: 
# The system is out of physical RAM or swap space 
# In 32 bit mode, the process size limit was hit 
# Possible solutions: 
# Reduce memory load on the system 
# Increase physical memory or swap space 
# Check if swap backing store is full 
# Use 64 bit Java on a 64 bit OS 
# Decrease Java heap size (-Xmx/-Xms) 
# Decrease number of Java threads 
# Decrease Java thread stack sizes (-Xss) 
# Set larger code cache with -XX:ReservedCodeCacheSize= 
# This output file may be truncated or incomplete. 
# 
# JRE version: 6.0_24-b24 
# Java VM: OpenJDK 64-Bit Server VM (20.0-b12 mixed mode linux-amd64 compressed oops) 
# Derivative: IcedTea6 1.11.1 
# Distribution: Fedora release 16 (Verne), package fedora-65.1.11.1.fc16-x86_64 
+0

Является ли ServerThread экземпляром java.lang.Thread? то он должен быть запущен с Thread.start(), и пул потоков бесполезен. Если нет, то как вы собираетесь обслуживать соединение сокета с простым Runnable? Это сложно, так как задачи под управлением threadpool не могут дождаться ввода, или может возникнуть головоломка потока (вид взаимоблокировки). –

+0

ServerThread - это плохо названный класс моего собственного создания. Public class ServerThread реализует Runnable {... public void run() {...} ...} ' Я вижу вашу обеспокоенность в связи с тем, что может быть плохо ждать вход в пул (есть функция тайм-аута), но я не хочу создавать новый поток каждый раз, когда клиент подключается, - это было бы огромными накладными расходами для относительно коротких взаимодействий и все равно не решило бы проблемы с созданием потоков. – kaz

+0

Вы проверили, сколько потоков вы можете создать в более простом приложении? – Jivings

ответ

11

Вы можете быть ограничение на max user processes, чтобы знать свой предел использования:

ulimit -u 

Чтобы изменить предел:

В /etc/security/limits.conf комплекте:

user soft nproc [your_val] 
user hard nproc [your_val] 

Вы, возможно, придется добавить некоторые другой конфигурации, если этого недостаточно, см. это link.

Примечание: ОП нашел это bug report в fedora и centos, что объясняет ограничения редактирования /etc/security/limits.conf.

+0

Я был бы поврежден, если это * является причиной моей головной боли с версией Centos 6, которую я использую. подстановочный знак (*) наказан в дикой природе. Не только я, но и сторонники поддержки, по-видимому, не знали об этом – nir

3

Возможно, проблема связана с тем, что JVM не может выделить стек для новых потоков. По иронии судьбы, эта проблема может быть решена путем уменьшения пространства кучи (-Xmx) и пространства стека (-Xss). Проверьте здесь, например, за хорошее объяснение: http://www.blogsoncloud.com/jsp/techSols/java-lang-OutOfMemoryError-unable-to-create-new-native-thread.jsp

+0

Хотелось бы, чтобы все было так просто, но как-то с помощью '-Xmx1G -Xss104k'I удалось создать 6 потоков (всего 40 явно созданных в моей программе).104k - минимальное значение -Xss в моей системе, а 1G нигде не так велико, как должно быть в производстве. Между тем в системе все еще остается огромное количество (более 8G), когда у него заканчивается память. – kaz

+0

104k - странное значение :) этот документ рассказывает о минимальном значении 64k http://www.oracle.com/technetwork/java/hotspotfaq-138619.html#threads_oom –

+0

Странно, но когда я запускаю JVM с менее чем 104, выдает это сообщение и сбой: 'Указанный размер стека слишком мал, укажите не менее 104k Не удалось создать виртуальную машину Java.' – kaz

3

Это не пропавшая память для ваших новых потоков, ей не хватает фактических потоков. Система, вероятно, останавливает вас: существует ограничение на количество потоков, которые пользователь может создать.Вы можете запросить его таким образом:

cat /proc/sys/kernel/threads-max 

Заметьте, что вы могли бы быть затронуты другими процессами на ту же машину, вы, они создают много нити тоже. Вы могли бы найти этот вопрос полезным: Maximum number of threads per process in Linux?

+0

'$ cat/proc/sys/kernel/threads-max' возвращает 385345- на сервере запуск моей программы, несколько оболочек ssh/bash и MySQL, я не думаю, что я нажимаю этот предел. Кроме того, некоторые особенно ужасные настройки jvm заставляют его умереть после того, как было создано меньшее количество потоков, чем другие, что говорит о том, что это проблема JVM. – kaz

1

Просто для уточнения:

Вы предоставляете ServerSocket в Thread. Вы отправляете данные в этот сокет? Возможно, вы храните много данных в контексте Thread-Context. Посмотрите на шаблон, в котором вы храните Streamdata в byte[].

+0

Нет, я предоставляю 'Socket' в поток,' ServerSocket.accept() 'возвращает объект' Socket'. И да, я передаю ему данные из другой программы и читаю эти данные, обрабатываю их, а затем отключаю. В тестовой версии поток просто принимает сокет, ждет, затем закрывает его и умирает. Сокет читается как поток, поэтому я не думаю, что передаю все содержимое этого потока в поток. Более того, пока клиент не аутентифицируется, он не отправляет данные, а в буфер потока будет всего несколько сотен байтов. – kaz

Смежные вопросы