Spring Boot SFTP转S3任务后内存/磁盘未释放,疑资源未正确关闭
内存与磁盘占用未回落的资源泄漏问题排查与修复
你的代码确实存在几处资源未正确清理的问题,导致任务完成后内存和磁盘占用无法回落:
问题点及修复方案
- 临时文件未主动清理:
tempFile.deleteOnExit()仅在JVM进程退出时才会删除文件,但Cloud Foundry环境下应用进程不会频繁退出,这会导致临时文件持续占用磁盘空间。需要在文件上传S3完成后主动删除临时文件,同时处理删除时的异常。 - InputStream未通过try-with-resources管理:当前手动调用
inputStream.close(),但如果IOUtils.copy或s3bucket.putObject抛出异常,close()可能无法执行,导致SFTP输入流资源泄漏,进而占用内存。 - 重复关闭流:
try (FileOutputStream outputStream = ...)已经会自动关闭输出流,手动调用outputStream.close()和outputStream.flush()属于多余操作,甚至可能引发IOException。
修复后的代码
Vector<ChannelSftp.LsEntry> files = sftpChannel.ls("*.csv"); if (!files.isEmpty()) { try { for (ChannelSftp.LsEntry file : files) { String fileName = file.getFilename(); String newName = stamp + "_" + fileName; final File tempFile = File.createTempFile("stream2file", "tmp"); // 将InputStream和OutputStream都纳入try-with-resources,自动关闭资源 try (InputStream inputStream = sftpChannel.get(fileName); FileOutputStream outputStream = new FileOutputStream(tempFile)) { IOUtils.copy(inputStream, outputStream); s3bucket.putObject(new PutObjectRequest("TEST", newName, tempFile)); // 上传完成后主动删除临时文件 if (!tempFile.delete()) { LOGGER.log(Level.WARNING, "无法删除临时文件: " + tempFile.getAbsolutePath()); } } catch (IOException e) { LOGGER.log(Level.WARNING, "处理文件 " + fileName + " 出错: ", e); // 异常时也要尝试删除临时文件,避免磁盘泄漏 if (tempFile.exists() && !tempFile.delete()) { LOGGER.log(Level.WARNING, "异常时无法删除临时文件: " + tempFile.getAbsolutePath()); } } } } catch (FileNotFoundException e) { LOGGER.log(Level.INFO, "未找到目标文件"); } catch (IOException e) { LOGGER.log(Level.INFO, "IO操作异常"); } finally { // 先判断连接状态再断开,避免重复操作引发异常 if (channel != null && channel.isConnected()) { channel.disconnect(); LOGGER.log(Level.INFO, "SFTP通道已断开"); } if (session != null && session.isConnected()) { session.disconnect(); LOGGER.log(Level.INFO, "SFTP会话已断开"); } } }
额外优化建议
- 考虑使用S3的流式上传能力,无需生成临时文件,彻底避免磁盘占用问题,同时减少内存开销:
// 直接上传InputStream到S3,跳过临时文件步骤 s3bucket.putObject(new PutObjectRequest("TEST", newName, inputStream, new ObjectMetadata()) .withCannedAcl(CannedAccessControlList.Private)); - 对大文件可以考虑分段上传,进一步降低单文件处理的内存占用。
内容的提问来源于stack exchange,提问作者Andre S
相关产品推荐
相关产品推荐

