java - 是否保证会抛出 Java OutOfMemoryError
问题描述
我有一个 Java Spring Boot 应用程序。它具有许多服务的真正大型应用程序,并且可以执行大量任务。我正在尝试实施的一项新任务是从 Oracle DB 中读取一些数据并通过 rest 将其发送到某个外部应用程序。
正在读取的数据非常大(很难说有多大,它包含几何对象),大约有 180 万条记录要读取。
为了处理这个问题,我使用“keyset pagination”作为从 DB 读取的一种方式。这意味着我获得了最后读取的 id,然后根据它获得下一页(e_id > lastReadId)。页面大小为 100 个实体。
在最后一次运行中,它到达了“6672”页(已读取 667200 个实体并将其发送到外部应用程序)。值得注意的是,我不存储对这些对象的任何引用,只是获取一个页面,将其存储为列表并通过 rest 发送。在下一次运行时,该列表将被新页面覆盖,依此类推。
这是每 3 小时获取的实体数量的图表,最多为 1030 个,最少为 145 个实体。
我的问题是应用程序崩溃而没有任何错误。在日志中,我可以看到最后一页已被获取(在本例中是“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
解决方案
您可以将 JVM 配置为在收到此错误时生成堆转储。
要配置 JVM 以生成堆转储,请将 -XX:+HeapDumpOnOutOfMemoryError 选项添加到 Java 选项并重新启动 JVM。当发生堆空间错误时,JVM 会创建一个大小为配置的最大堆大小的文件。
推荐阅读
- gsm - SIM7600 串行端口多路复用器与 Beaglebone
- android - Fabric Plugin 是幻影
- java - @BeforeAll 和 @Transaction 不起作用 - 数据库端的更改不会回滚
- amazon-web-services - AWS ECS 使用 CloudFormation 担任角色。在 ECS 中部署的 Docker 微服务在哪里获得假定角色?
- android - 如何查询where-greater-than然后按firestore中的另一个文档值对其进行排序?
- python - Oozie shell 动作创建 python 虚拟环境
- typescript - 当我知道 `this` 是动态的时,我可以使用 Typescript 强制使用经典函数作为参数而不是箭头函数吗?
- java - 如何使用java从字符位置获取文件中的行号
- javascript - 使用javascript循环更改单词最后一个字符的颜色
- vue.js - 如何将数组参数传递给 url VueJs