是否保证会抛出 Java OutOfMemoryError
Is there a guarantee that Java OutOfMemoryError will be thrown
我有一个 Java Spring 启动应用程序。它是一个非常大的应用程序,具有许多服务,并且可以执行大量任务。我试图实现的新任务之一是从 Oracle DB 读取一些数据并通过 rest 将其发送到某个外部应用程序。
正在读取的数据比较大(很难说有多大,里面有几何对象),大约有180万条记录要读取。
为了处理这个问题,我使用 "keyset pagination" 作为从数据库读取的一种方式。这意味着我获得了上次读取的 ID,然后基于该 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。当堆 space 错误发生时,JVM 创建一个文件,其大小为配置的最大堆大小。
在使用 JProfiler 进行一些分析后,我发现 Hibernate 会缓存所有选定的内容,因为所有内容都是在单个事务中完成的。在现有的 while 循环中添加 EntityManager.clear() 解决了问题。
另外值得注意的是,整个过程显着加快。
我有一个 Java Spring 启动应用程序。它是一个非常大的应用程序,具有许多服务,并且可以执行大量任务。我试图实现的新任务之一是从 Oracle DB 读取一些数据并通过 rest 将其发送到某个外部应用程序。
正在读取的数据比较大(很难说有多大,里面有几何对象),大约有180万条记录要读取。
为了处理这个问题,我使用 "keyset pagination" 作为从数据库读取的一种方式。这意味着我获得了上次读取的 ID,然后基于该 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。当堆 space 错误发生时,JVM 创建一个文件,其大小为配置的最大堆大小。
在使用 JProfiler 进行一些分析后,我发现 Hibernate 会缓存所有选定的内容,因为所有内容都是在单个事务中完成的。在现有的 while 循环中添加 EntityManager.clear() 解决了问题。
另外值得注意的是,整个过程显着加快。