Hacktoberfest 2026:メンテナが10月に向けて印を付けた、オープンで初心者向けの issue。 Hacktoberfest の issue を見る

[BUG] - Java-Chassis 新版本无法自动清理临时上传文件的句柄

オープン
#4,835 コメント 4 件 リアクション 0 件 担当者 0 名 GitHub で見る

まだ誰も着手していません。

評価

難易度
5/5
見積もり時間
1週間以上
初心者へのやさしさ
35/100
issue の種類
バグ
明瞭さ
おおむね明確
活発さ
停滞
技術スタック
java
領域
api, backend

調査の方向性

foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/http/FileUploadPart.java から始め、issue #4476 に関連する変更を確認してください。Linux 上で Java-Chassis 2.8.24 を使用してハンドル保持の動作を再現し、その後、非同期アップロード処理を壊すことなく Java 8 と Java 21 との互換性を維持できるクリーンアップ設計を決定して検証してください。

索引モデルが issue の本文から書いたものです。

説明

bug
Steps to Reproduce
  1. 编写一个处理文件上传请求的controller.
  2. 接收到上传文件参数后, 打开文件流, 不关闭, 直接返回.
  3. 在Java-Chassis 1.x分支上可以观察到一段时间后文件句柄会被清理, 而在 Java-Chassis 2.8.24 版本, 文件句柄会一直存在, 直到进程重启才会消失.

注意:

  1. 实际测试发现此问题在Windows上不会出现(Java8), 我们是在Linux上复现的问题.
  2. 打开文件流不关闭只是为了让问题必现. 实际上即使业务代码有正常的close调用也可能遇到类似的问题, 因为业务处理文件流的逻辑可能超时, 导致 Vert.x 执行临时文件清理回调时文件流仍然处于打开的状态.
Expected Behavior

预期 Java-Chassis 2.8.24 能像 Java-Chassis 1.x 分支一样, 能够自动兜底清理文件句柄.

Servicecomb Version

2.8.24

Additional Context

根因分析

导致 Java-Chassis 1.x 和 2.8.x 差异的代码在于:

https://github.com/apache/servicecomb-java-chassis/blob/6873ee5992ff2211a1e0efa33dd30377a914ecbf/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/http/FileUploadPart.java#L37-L40

在更早的版本中, 它返回的是一个 FileInputStream:

https://github.com/apache/servicecomb-java-chassis/blob/f3dc998d78394fec8d6755192a57ab7ea889b859/foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/http/FileUploadPart.java#L37-L40

而 2.8.20 版本对此做了上述修改, 实测返回的是 sun.nio.ch.ChannelInputStream 类型的流.

在 Java8 中, FileInputStream 的 finalize 方法会执行 close 方法, 而 sun.nio.ch.ChannelInputStream 的 finalize 方法是空的. 这就导致 Java-Chassis 2.8.19 及之前的版本, 即使业务代码由于各种各样的原因没有执行 close 方法, FileInputStream 也能在被GC回收时兜底关闭文件句柄, 而在升级到 Java-Chassis 2.8.20 之后就只能泄漏句柄了.

回溯 Java-Chassis 的代码修改记录可知, 这个变化是为了修复另外一个问题而引入的:
https://github.com/apache/servicecomb-java-chassis/issues/4476

解决思路

Java-Chassis 已经不适合将文件输入流的类型改回 FileInputStream 了.

除了上面说的 issue #4476 的原因, 高版本的 Java 还废弃了 finalize 方法, 即使用回 FileInputStream 也不能兜底关闭文件句柄.
为了能够同时兼容 Java8 和 Java21, 也不适合选用 Cleaner 机制(Java9才具备此特性).

目前能想到的解决办法:

  1. 基于 Java-Chassis 自身的 Invocation 生命周期管理机制来做自动清理动作.

    此方案的风险在于, 考虑到业务可能在 controller 层获取上传文件参数后, 异步调度到其他任务线程池处理, 因此在 Invocation 的结束事件发生时就直接关闭流的话可能会导致业务视角看到的Java-Chassis框架行为发生了影响业务功能的不兼容变化.

  2. 记录已打开的 InputStream, 在后台定时任务中监控其关闭状态.

    此方案可以一定程度规避方案1的风险, 但存在内存用量上升甚至泄漏的风险, 若选择这个思路, 也需要小心进行可靠性设计.

此外, 建议Java-Chassis增加对 FileUploadPart 的打开流的调用记录的监控, 便于辅助业务分析此类文件句柄泄漏问题的触发代码位置.

主要言語
Java
スター
1.9k
フォーク
813
平均マージ
8日 23時間
マージ済み PR(30日)
1

コントリビューションガイド

このリポジトリのコントリビューションガイドは索引されていません

はじめの一歩

  1. issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
  2. 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
  3. リポジトリをフォークし、ブランチを切って変更します。
  4. issue 番号を参照したプルリクエストを送ります。

apache/servicecomb-java-chassis のほかの issue

apache/servicecomb-java-chassis の issue をすべて見る

似ている issue

Java の issue をもっと見る

新しい issue をメールで受け取る

初心者向けの GitHub issue を短くまとめたダイジェスト。