OutOfMemoryError, хотя свободной памяти достаточно

Я получаю ошибки java.lang.OutOfMemoryError, даже если у меня еще достаточно свободной оперативной памяти. Дампы памяти, которые я взял, были от 200 МБ до 1 ГБ, а у моего сервера 24 ГБ ОЗУ. Я поставил -Xmx12288m -Xms12288m.

Кроме того, когда я пытаюсь войти на сервер, я часто получаю

-bash: fork: retry: Resource temporarily unavailable
-bash: fork: retry: Resource temporarily unavailable
-bash: fork: retry: Resource temporarily unavailable
-bash: fork: retry: Resource temporarily unavailable
-bash: fork: Resource temporarily unavailable

Я сузил его до фрагмента кода ниже:

import org.snmp4j.Snmp;
import org.snmp4j.transport.DefaultUdpTransportMapping;

    long n = 0;
    while (true) {
        DefaultUdpTransportMapping transport = null;
        try {
            transport = new DefaultUdpTransportMapping();
            transport.listen();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
//      } finally {             // (*) I forgot this
//          transport.close();  // (*) I forgot this
        }

        n++;
        double freeMemMB = Runtime.getRuntime().freeMemory() / 1024 / 1024;
        System.out.println("Created " + n
                + " DefaultUdpTransportMappings. Free Mem (mb): "
                + freeMemMB);
    }

Вывод (на моей машине разработчика с mvn exec:java):

Created 2026 DefaultUdpTransportMappings. Free Mem (mb): 299.0
Created 2027 DefaultUdpTransportMappings. Free Mem (mb): 299.0
[WARNING] 
java.lang.reflect.InvocationTargetException
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:606)
    at org.codehaus.mojo.exec.ExecJavaMojo$1.run(ExecJavaMojo.java:293)
    at java.lang.Thread.run(Thread.java:745)
Caused by: 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 org.snmp4j.util.DefaultThreadFactory$WorkerThread.run(DefaultThreadFactory.java:91)
    at org.snmp4j.transport.DefaultUdpTransportMapping.listen(DefaultUdpTransportMapping.java:168)
    at App.main(App.java:19)
    ... 6 more

Я обнаружил, что получаю ошибки, потому что не закрываю файл DefaultUdpTransportMapping. Включение блока finally { ... } решает проблему. Теперь мне интересно, каких пределов (если не количества свободной памяти) я достиг. ulimits на сервере:

core file size          (blocks, -c) 0
data seg size           (kbytes, -d) unlimited
scheduling priority             (-e) 0
file size               (blocks, -f) unlimited
pending signals                 (-i) 191968
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) 10240
cpu time               (seconds, -t) unlimited
max user processes              (-u) 1024
virtual memory          (kbytes, -v) unlimited
file locks                      (-x) unlimited

На моем Mac разработчика:

-t: cpu time (seconds)              unlimited
-f: file size (blocks)              unlimited
-d: data seg size (kbytes)          unlimited
-s: stack size (kbytes)             8192
-c: core file size (blocks)         0
-v: address space (kbytes)          unlimited
-l: locked-in-memory size (kbytes)  unlimited
-u: processes                       709
-n: file descriptors                2560

Какого предела я достиг?


person Benedikt Köppel    schedule 19.11.2014    source источник
comment
На что настроен ваш -Xmx?   -  person Oliver Charlesworth    schedule 19.11.2014
comment
Локально у меня есть -Xmx1024m. Когда я устанавливаю для него значение -Xmx2048m, я все равно получаю ошибку OutOfMemoryError после запуска 2027 DefaultUdpTransportMappings. Для производственного процесса на сервере я поставил -Xmx12288m -Xms12288m. Дамп памяти производственного процесса составляет 58 МБ.   -  person Benedikt Köppel    schedule 19.11.2014
comment
запустите снова и подключите jconsole (поставляется с jdk) к запущенному процессу; если вы добавите к нему визуальный плагин gc, он покажет вам размеры и количество выделений в каждой области кучи.   -  person Chris K    schedule 19.11.2014
comment
возможный дубликат Java: невозможно создать новый собственный поток   -  person Erich Kitzmueller    schedule 19.11.2014
comment
Я не смог узнать, как добавить VisualGC в jconsole, но нашел его в jvisualvm. Вот как это выглядит: i.imgur.com/OvIko5w.png.   -  person Benedikt Köppel    schedule 19.11.2014
comment
ammoQ: В ссылке упоминается, что я достиг предела для дескрипторов открытых файлов. Я попытался распечатать количество открытых FD с кодом отсюда: stackoverflow.com/a/16361505/1067124. Я получаю OutOfMemoryError, когда у меня есть 2098 открытых FD. ulimit для открытых FD — 2560.   -  person Benedikt Köppel    schedule 19.11.2014
comment
@BenediktKöppel, вы также должны прочитать связанную запись в блоге blog.egilh.com/2006/06/ 2811aspx.html   -  person Erich Kitzmueller    schedule 19.11.2014


Ответы (1)


Сообщение java.lang.OutOfMemoryError: unable to create new native thread сбивает с толку, так как на самом деле оно не связано с нехваткой памяти в куче. Поэтому настройки размера кучи (Xmx и Xms) в этом случае не влияют. Исключение возникает, когда новый рабочий процесс не может быть создан для вашего приложения, либо из-за того, что достигнуто максимальное количество процессов/открытых файловых дескрипторов, либо в системе не осталось памяти для создания нового потока.

Что касается настроек ulimit, это может быть либо количество файловых дескрипторов, размер стека, либо количество процессов. Размер стека - это количество потоков на число, количество потоков, умноженное на размер стека, будет объемом используемой памяти.

Обычно, как и в вашем случае, получение этого исключения означает, что ваше приложение не закрывает свои потоки должным образом и удерживает системные процессы. Вот почему закрытие транспорта решило проблему для вас.

person Erwin de Gier    schedule 19.03.2015