Есть ли гарантия, что Java OutOfMemoryError будет выброшен

У меня есть приложение Java Spring Boot. Это действительно большое приложение с множеством сервисов, которое может выполнять кучу задач. Одна из новых задач, которую я пытаюсь реализовать, - это прочитать некоторые данные из Oracle DB и отправить их через rest в какое-то внешнее приложение.

Считываемые данные довольно большие (трудно сказать, насколько они велики, они содержат геометрические объекты), и необходимо прочитать около 1,8 миллиона записей.

Чтобы справиться с этим, я использую «разбиение на страницы» как способ чтения из БД. Это означает, что я получаю последний идентификатор чтения, а затем на его основе получаю следующую страницу (e_id> lastReadId). Размер страницы 100 объектов.

При последнем запуске он дошел до страницы «6672» (667200 сущностей были прочитаны и отправлены во внешнее приложение). Стоит отметить, что я не храню никаких ссылок на эти объекты, просто получаю страницу, сохраняю ее в списке и отправляю через rest. При следующем запуске этот список заменяется новой страницей и так далее.

Вот график количества извлеченных сущностей за 3 часа, максимум 1030 и минимум 145 сущностей.

Есть ли гарантия, что Java OutOfMemoryError будет выброшен

Моя проблема в том, что приложение вылетает без ошибок. В журналах я вижу, что была получена последняя страница (в данном случае это была «6672», иногда это была другая страница), а затем внезапно появляется сообщение журнала, которое регистрируется при запуске моего приложения.

Первой моей мыслью было, что у него закончилась память и он просто вылетел. Но на это нет никаких указаний. Гарантируется ли, что в такой момент будет сгенерировано OutOfMemoryError? Стоит ли мне посмотреть на что-нибудь еще? Может я что-то не так делаю.

РЕДАКТИРОВАТЬ

Я добавляю код, чтобы вы увидели, как я выполняю эти действия

// Get first page, last read id is null
List<MyEntity> data = dataService.collectData(pageSize, null);

sendDataToExternalService(data);
while(true) {
    final String lastReadID = data.get(data.size() - 1).getId();
    data = dataService.collectData(pageSize, lastReadID);
    sendDataToExternalService(data);
}

Метод sendDataToExternalService выглядит так

restTemplate.exchange("some/url/to-external-app", HttpMethod.PUT, new HttpEntity<>(data), List.class);

RestTemplate: org.springframework.web.client.RestTemplate

Думаю, лучше будет, если вы загрузите их частично, а не загрузите огромное количество записей? После обработки можно загружать дальше?

Gaurav Srivastav 17.09.2018 07:37

Похоже на проблему с утечкой памяти. Вы пробовали анализировать это с помощью такого инструмента, как VisualVM?

Raman Sahasi 17.09.2018 07:38

Это было запущено на одном из наших серверов, теперь я пытаюсь настроить все локально на моем ПК, запустить его с помощью VisualVM и попытаться посмотреть, что произойдет.

mirzak 17.09.2018 08:01

Когда базовая ОС обнаруживает блокировки или чрезмерное использование памяти, она может просто завершить процесс. Это без того, чтобы вы видели исключения OOM и т. д., Поэтому это зависит от того, что убивает процесс. Кроме того, если у вас много результатов, вы должны передавать результат в потоковом режиме, а не буферизовать его все на клиенте. Добавьте код к вашему вопросу, чтобы увидеть, как вы создаете запрос и читаете результаты.

M. Deinum 17.09.2018 09:02
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
0
4
125
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Вы можете настроить JVM на создание дампа кучи при получении этой ошибки.

Чтобы настроить JVM для создания дампа кучи, добавьте параметр -XX: + HeapDumpOnOutOfMemoryError в параметры Java и перезапустите JVM. Когда возникает ошибка пространства кучи, JVM создает файл размером с настроенный максимальный размер кучи.

Проверьте это для подробностей https://docs.bmc.com/docs/AtriumOrchestratorPlatform/77/troubleshooting-java-virtual-machine-memory-errors-329147248.html

Ответ принят как подходящий

После некоторого профилирования с использованием JProfiler я смог узнать, что Hibernate кэширует все, что было выбрано, поскольку все выполнялось за одну транзакцию. Добавление EntityManager.clear () в существующий цикл while решило проблему.

Также стоит отметить, что весь процесс был значительно ускорен.

Другие вопросы по теме