我正在为我的网络应用程序开发上传图像功能,并且在 apache commons fileupload 的“FileCleaningTracker”中遇到了一个奇怪的问题。我有一个带有实例变量 FileCleaningTracker 的 ImageUploadService,然后我有一个创建 DiskFileItemFactory 实例然后引用 FileCleaningTracker 的上传方法,在上传方法成功完成后,我将 DiskFileItemFactory 的 FileCleaningTracker 设置为 null,所以我希望 DiskFileItemFactory进行垃圾收集,然后将通知 FileCleaningTracker 中 PhantomReference 的底层子类,因此删除 DiskFileItemFactory 创建的临时文件。
但这不会发生,直到我在上传方法结束时将 DiskFileItemFactory 清空并调用 System.gc() (仅清空 DiskFileItemFactory 没有帮助)。这对我来说似乎很奇怪。这是我的代码:
@Override
public void upload(final HttpServletRequest request) {
ValidateUtils.checkNotNull(request, "upload request");
final File tmp = new File(this.tempFolder);
if (!tmp.exists()) {
tmp.mkdir();
}
DiskFileItemFactory fileItemFactory = new DiskFileItemFactory(this.sizeThreshold, tmp);
fileItemFactory.setFileCleaningTracker(this.fileCleaningTracker);
ServletFileUpload uploadHandler = new ServletFileUpload(fileItemFactory);
List items;
try {
items = uploadHandler.parseRequest(request);
} catch (final FileUploadException e) {
throw new ImageUploadServiceException("Error parsing the http servlet request for image upload.", e);
}
final Iterator it = items.iterator();
while (it.hasNext()) {
final DiskFileItem item = (DiskFileItem) it.next();
if (item.isFormField()) {
// log message
} else {
final String fileName = item.getName();
final File destination = this.createFileForUpload(fileName, this.uploadFolder);
FileChannel outChannel;
try {
outChannel = new FileOutputStream(destination).getChannel();
} catch (final FileNotFoundException e) {
throw new ImageUploadServiceException(e);
}
FileChannel inChannel = null;
try {
inChannel = new FileInputStream(item.getStoreLocation()).getChannel();
outChannel.transferFrom(inChannel, 0, item.getSize());
} catch (final IOException e) {
throw new ImageUploadServiceException(String.format("Error uploading image to '%s/%s'.", this.uploadFolder, destination.getName()), e);
} finally {
IOUtils.closeChannel(inChannel);
IOUtils.closeChannel(outChannel);
}
}
}
fileItemFactory.setFileCleaningTracker(null);
}
上面的代码导致每次上传都会在临时文件夹中创建一个文件,但最后不会被“fileCleaningTracker”删除,可能是因为 DiskFileItemFactory 实例没有被垃圾收集(我看不出为什么它不应该有)或者它已被 GCed 但未由 fileCleaningTracker 中的 PhantomReference 通知(PhantomReference 的可靠性如何?)
我等了10分钟,文件还在,应该不是GC没有运行的原因。并且没有例外。
现在,如果我添加以下代码,则每次上传后都会删除临时文件:
fileItemFactory = null;
System.gc();
这对我来说看起来很奇怪,因为我希望在没有显式调用 System.gc() 的情况下对 fileItemFactory 进行 GC。
任何输入将不胜感激。
谢谢你。