是否保证会抛出Java OutOfMemoryError
我有一个JavaSpring启动应用程序。它的应用程序非常大,有很多服务,可以执行一系列任务。我尝试实现的新任务之一是从Oracle DB读取一些数据,并通过rest将其发送到某个外部应用程序 正在读取的数据非常大(很难说有多大,它包含几何体对象),大约有180万条记录需要读取 为了处理这个问题,我使用“键集分页”作为从数据库读取数据的一种方式。这意味着我得到最后一个读取id,然后根据该id获得下一页(e_id>lastReadId)。页面大小为100个实体 上一次运行时,它到达了“6672”页(667200个实体已被读取并发送到外部应用程序)。值得注意的是,我不存储对这些对象的任何引用,只需获取一个页面,将其存储为列表,然后通过rest发送。在下一次运行时,该列表将被一个新页面覆盖,以此类推 下面是每3小时获取的实体数的图表,最大为1030个,最小为145个 我的问题是,应用程序崩溃时没有任何错误。在日志中,我可以看到最后一页已被提取(在本例中是“6672”,有时是其他页面),然后突然出现一条日志消息,在我的应用程序启动时记录 我的第一个想法是,它耗尽了内存,只是崩溃了。但没有迹象表明这一点。是否保证在此点抛出OutOfMemoryError? 我应该看看别的东西吗?也许我做错了什么 编辑 我正在添加一些代码,让您了解我是如何执行这些操作的是否保证会抛出Java OutOfMemoryError,java,spring,crash,out-of-memory,Java,Spring,Crash,Out Of Memory,我有一个JavaSpring启动应用程序。它的应用程序非常大,有很多服务,可以执行一系列任务。我尝试实现的新任务之一是从Oracle DB读取一些数据,并通过rest将其发送到某个外部应用程序 正在读取的数据非常大(很难说有多大,它包含几何体对象),大约有180万条记录需要读取 为了处理这个问题,我使用“键集分页”作为从数据库读取数据的一种方式。这意味着我得到最后一个读取id,然后根据该id获得下一页(e_id>lastReadId)。页面大小为100个实体 上一次运行时,它到达了“6672”页
// 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);
}
RestTemplate是org.springframework.web.client.RestTemplate您可以将JVM配置为在收到此错误时生成堆转储 要将JVM配置为生成堆转储,请将-XX:+heapdumponAutofmemoryError选项添加到Java选项中,然后重新启动JVM。当发生堆空间错误时,JVM将创建一个文件,其大小为配置的最大堆大小 查看此以了解详细信息
在使用JProfiler进行了一些评测之后,我发现Hibernate将缓存所选的所有内容,因为所有内容都是在单个事务中完成的。在现有while循环中添加EntityManager.clear(),解决了该问题
另外,值得注意的是,整个过程大大加快了。我认为最好是部分加载,而不是加载大量记录?处理后,您可以进一步加载?这似乎是内存泄漏问题。您是否尝试使用VisualVM之类的工具进行分析?这是在我们的一台服务器上运行的,我现在正在尝试在我的PC上本地设置所有内容,并使用VisualVM运行它,并尝试查看当底层操作系统检测到锁或过度内存使用时会发生什么情况。这是因为您没有看到OOM异常等,所以这取决于是什么扼杀了进程。此外,如果您有很多结果,您应该将结果流式传输,而不是在客户端上缓冲所有结果。请在您的问题中添加一些代码,以查看您是如何创建请求和阅读结果的。
restTemplate.exchange("some/url/to-external-app", HttpMethod.PUT, new HttpEntity<>(data), List.class);