Hacktoberfest 2026: die Issues, die Maintainer für den Oktober markiert haben – offen und einsteigerfreundlich. Hacktoberfest-Issues durchsuchen

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

Offen
#4,835 4 Kommentare 0 Reaktionen 0 zugewiesene Personen Auf GitHub ansehen

Dieses Issue hat noch niemand übernommen.

Bewertung

Schwierigkeit
5/5
Geschätzter Aufwand
Über eine Woche
Anfängerfreundlichkeit
35/100
Issue-Typ
Bug
Klarheit
Größtenteils klar
Aktivitätsstatus
Veraltet
Tech-Stack
java
Bereich
api, backend

Rechercherichtung

Beginnen Sie mit foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/http/FileUploadPart.java und überprüfen Sie die mit Issue #4476 verbundene Änderung. Reproduzieren Sie das Verhalten der Handle-Beibehaltung unter Linux mit Java-Chassis 2.8.24 und ermitteln und validieren Sie anschließend ein Cleanup-Design, das mit Java 8 und Java 21 kompatibel bleibt, ohne die asynchrone Upload-Verarbeitung zu beeinträchtigen.

Vom Indexierungsmodell aus dem Issue-Text verfasst.

Beschreibung

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 的打开流的调用记录的监控, 便于辅助业务分析此类文件句柄泄漏问题的触发代码位置.

Vorherrschende Sprache
Java
Sterne
1.9k
Forks
813
Ø Merge
8 T. 23 Std.
Gemergte PRs (30 T.)
1

Beitragsleitfaden

Für dieses Repository ist kein Beitragsleitfaden indexiert

Erste Schritte

  1. Lesen Sie das ganze Issue und danach den Beitragsleitfaden des Projekts.
  2. Schreiben Sie ins Issue, dass Sie es übernehmen — das erspart doppelte Arbeit.
  3. Forken Sie das Repository und arbeiten Sie in einem Branch.
  4. Öffnen Sie einen Pull Request, der die Issue-Nummer nennt.

Mehr aus apache/servicecomb-java-chassis

Alle Issues in apache/servicecomb-java-chassis

Ähnliche Issues

Weitere Issues zu Java

Neue Issues direkt in Ihr Postfach

Eine kurze Übersicht über anfängerfreundliche GitHub-Issues.