На работе одна из наших целевых платформ - это ограниченный ресурсами мини-сервер под управлением Linux (ядро 2.6.13, настраиваемый дистрибутив на базе старого Fedora Core). Приложение написано на Java (Sun JDK 1.6_04). Убийца Linux OOM настроен на то, чтобы убивать процессы, когда использование памяти превышает 160 МБ. Даже при высокой нагрузке наше приложение никогда не выходит за 120 Мбайт и вместе с некоторыми другими активными процессами, которые активны, мы остаемся в пределах предела OOM.
Однако, оказывается, что метод Java Runtime.getRuntime(). exec(), канонический способ выполнения внешних процессов с Java, имеет в частности неудачная реализация в Linux, которая вызывает порождаемые дочерние процессы (временно), требует того же объема памяти, что и родительский процесс, поскольку адресное пространство копируется. Конечным результатом является то, что наше приложение будет убито убийцей OOM, как только мы выполним Runtime.getRuntime(). Exec().
В настоящее время мы работаем над этим, имея отдельную собственную программу, выполняющую все внешние команды, и мы общаемся с этой программой через сокет. Это менее оптимально.
После публикация об этой проблеме в Интернете У меня появилась некоторая обратная связь, указывающая на то, что это не должно происходить в "новых" версиях Linux, поскольку они реализуют posix fork(), используя copy-on-write, предположительно означает, что он будет копировать только те страницы, которые необходимо изменить, когда это необходимо, вместо всего адресного пространства.
Мои вопросы:
- Это правда?
- Это что-то в ядре, реализация libc или где-то еще?
- В какой версии ядра /libc/what есть копирование на запись для fork()?