Hacktoberfest 2026 : les issues que les mainteneurs ont marquées pour octobre, ouvertes et accessibles aux débutants. Parcourir les issues Hacktoberfest

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

Ouverte
#4,835 4 commentaires 0 réactions 0 personnes assignées Voir sur GitHub

Personne n'a encore pris cette issue.

Évaluation

Difficulté
5/5
Temps estimé
Plus d'une semaine
Accessibilité débutants
35/100
Type d'issue
Bug
Clarté
Plutôt claire
Activité
À l'abandon
Stack technique
java
Domaine
api, backend

Piste de recherche

Commencez par foundations/foundation-vertx/src/main/java/org/apache/servicecomb/foundation/vertx/http/FileUploadPart.java et examinez la modification associée à l’issue #4476. Reproduisez le comportement de rétention des handles sous Linux avec Java-Chassis 2.8.24, puis déterminez et validez une conception de nettoyage qui reste compatible avec Java 8 et Java 21 sans interrompre le traitement asynchrone des uploads.

Rédigé par le modèle d'indexation à partir du texte de l'issue.

Description

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

Langage dominant
Java
Étoiles
1.9k
Forks
813
Merge moyen
8 j 23 h
PR mergées (30 j)
1

Guide de contribution

Aucun guide de contribution indexé pour ce dépôt

Par où commencer

  1. Lisez l'issue en entier, puis le guide de contribution du projet.
  2. Signalez en commentaire que vous la prenez — cela évite que deux personnes fassent le même travail.
  3. Forkez le dépôt et travaillez sur une branche.
  4. Ouvrez une pull request qui référence le numéro de l'issue.

Autres issues de apache/servicecomb-java-chassis

Toutes les issues de apache/servicecomb-java-chassis

Issues similaires

Plus d'issues Java

Recevez les nouvelles issues par e-mail

Un résumé court des issues GitHub adaptées aux débutants.