Повторные тайм-ауты с Java Future заставляют JVM исчерпать память - PullRequest
0 голосов
/ 24 апреля 2020

У нашего Java приложения возникает проблема, когда оно блокируется на неопределенный срок, когда оно пытается выполнить запись в файл журнала, расположенный на общем ресурсе NFS, а общий ресурс NFS недоступен.

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

public class write_with_future {
    public static void main(String[] args) {
        int iteration=0;
        while (true) {
            System.out.println("iteration " + ++iteration);

            ExecutorService executorService = Executors.newSingleThreadExecutor();
            Future future = executorService.submit(new Runnable() {
                public void run() {
                    try {
                        Category fileLogCategory = Category.getInstance("name");
                        FileAppender fileAppender = new FileAppender(new SimpleLayout(), "/usr/local/app/log/write_with_future.log");
                        fileLogCategory.addAppender(fileAppender);
                        fileLogCategory.log(Priority.INFO, System.currentTimeMillis());
                        fileLogCategory.removeAppender(fileAppender);
                        fileAppender.close();
                    }
                    catch (IOException e) {
                        System.out.println("IOException: " + e);
                    }
                }
            });

            try {
                future.get(100L, TimeUnit.MILLISECONDS);
            }
            catch (InterruptedException ie) {
                System.out.println("Current thread interrupted while waiting for task to complete: " + ie);
            }
            catch (ExecutionException ee) {
                System.out.println("Exception from task: " + ee);
            }
            catch (TimeoutException te) {
                System.out.println("Task timed out: " + te);
            }
            finally {
                future.cancel(true);
            }

            executorService.shutdownNow();
        }
    }
}

Когда я запустил эту программу с максимальным размером кучи 1 МБ, а общий ресурс NFS был запущен, эта программа смогла выполнить более 1 миллиона итераций, прежде чем Я остановил его.

Но когда я запустил программу с максимальным размером кучи 1 МБ, а общий ресурс NFS был недоступен, программа выполнила 584 итерации, каждый раз получая исключение TimeoutException, а затем с ошибкой java.lang.OutOfMemoryError ошибка. Поэтому я думаю, что даже при вызове future.cancel(true) и executorService.shutdownNow() потоки исполнителя блокируются при записи и не отвечают на прерывания, и программе в конечном итоге не хватает памяти.

Есть ли любой способ очистить потоки исполнителя, которые заблокированы?

1 Ответ

1 голос
/ 24 апреля 2020

Если кажется, что Thread.interrupt() не прерывает потоки, заблокированные в операции ввода-вывода для файла NFS. Возможно, вы захотите проверить параметры монтирования NFS, но я подозреваю, что вы не сможете решить эту проблему.

Однако вы наверняка можете предотвратить возникновение OOME. Причина, по которой вы их получаете, заключается в том, что вы не используете ExecutorService s, поскольку они предназначены для использования. Вы постоянно создаете и закрываете однопоточные сервисы. Что вы должны сделать, это создать экземпляр с ограниченным пулом потоков и использовать его для всех задач. Если вы сделаете это таким образом, если один из потоков займет много времени ... или заблокирован во время ввода-вывода ... вы не получите накопление потоков и не исчерпаете память. Вместо этого задания с ошибками будут находиться в рабочей очереди ExecutorService, пока один из рабочих потоков не разблокируется.

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