是否可以保证将抛出Java OutOfMemoryError

时间:2018-09-17 05:33:38

标签: java spring crash out-of-memory

我有一个Java Spring Boot应用程序。它是真正的大型应用程序,具有许多服务,并且可以执行许多任务。我要实现的新任务之一是从Oracle DB读取一些数据,然后通过其余部分将其发送到某个外部应用程序。

正在读取的数据非常大(很难分辨它包含几何对象的大小),并且大约有180万条记录要读取。

为了处理这一问题,我使用“键集分页”作为从DB读取的方式。这意味着我获得了上一个读取的ID,然后基于该ID获取了下一页(e_id> lastReadId)。页面大小为100个实体。

在最后一次运行时,页面显示为“ 6672”(已读取667200个实体并将其发送到外部应用程序)。值得注意的是,我不存储对这些对象的任何引用,只是获取页面,存储它的列表并通过rest发送它。在下一次运行时,该列表会被新页面覆盖,依此类推。

这里是每3小时获取的实体数的图表,最大为1030,最小为145。

Fetched entities per 3h

我的问题是该应用程序崩溃了,没有任何错误。在日志中,我可以看到已经提取了最后一页(在本例中为'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

2 个答案:

答案 0 :(得分:1)

您可以将JVM配置为在收到此错误时生成堆转储。

要配置JVM生成堆转储,请在Java选项中添加-XX:+ HeapDumpOnOutOfMemoryError选项,然后重新启动JVM。发生堆空间错误时,JVM将创建一个文件,其大小为配置的最大堆大小。

检查此项以获取详细信息 https://docs.bmc.com/docs/AtriumOrchestratorPlatform/77/troubleshooting-java-virtual-machine-memory-errors-329147248.html

答案 1 :(得分:0)

使用JProfiler进行性能分析后,我发现Hibernate将缓存所有选定的内容,因为所有事情都是在单个事务中完成的。在现有的while循环中添加 EntityManager.clear()解决了该问题。

另外值得注意的是,整个过程大大加快了。