Jvm org.apache.commons.io.FileCleaningTracker不会删除临时文件,除非显式调用System.gc()?

Jvm org.apache.commons.io.FileCleaningTracker不会删除临时文件,除非显式调用System.gc()?,jvm,Jvm,我正在为我的web应用程序开发一个上传图像功能,并且在apache commons fileupload的“FileCleaningTracker”中遇到了一个奇怪的问题。我有一个带有实例变量FileCleaningTracker的ImageUploadService,然后我有一个upload方法,该方法创建DiskFileItemFactory的实例,然后引用FileCleaningTracker,在upload方法成功完成后,我将DiskFileItemFactory的FileCleanin

我正在为我的web应用程序开发一个上传图像功能,并且在apache commons fileupload的“FileCleaningTracker”中遇到了一个奇怪的问题。我有一个带有实例变量FileCleaningTracker的ImageUploadService,然后我有一个upload方法,该方法创建DiskFileItemFactory的实例,然后引用FileCleaningTracker,在upload方法成功完成后,我将DiskFileItemFactory的FileCleaningTracker设置为null,因此,我希望对DiskFileItemFactory进行垃圾收集,然后会通知FileCleaningTracker中PhantomReference的底层子类,从而删除DiskFileItemFactory创建的临时文件

但是,直到我将DiskFileItemFactory设置为null并在upload方法结束时调用System.gc()(仅将DiskFileItemFactory设置为null没有帮助),这种情况才会发生。这对我来说似乎很奇怪。这是我的密码:

    @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实例没有被垃圾收集(我不明白为什么不应该被垃圾收集),或者它已经被GCD,但没有被fileCleaningTracker中的PhantomReference通知(幻影参考有多可靠?)

我等了10分钟,文件还在,所以不应该是因为GC没有运行,也没有例外

现在,如果我添加以下代码,每次上传后都会删除临时文件:

    fileItemFactory = null;
    System.gc();
这对我来说很奇怪,因为我希望fileItemFactory在没有显式调用System.gc()的情况下被GCed

如有任何意见,将不胜感激


谢谢。

我也有同样的问题。即使在服务器关闭后,临时文件也不会被删除:GC进程还没有启动,因此
文件清理tracker
没有机会从
引用队列
中删除跟踪文件,所有文件都保留在硬盘上

由于我的应用程序的特定行为,每次上传后我都必须清理(文件可能非常大)。我没有使用标准的
org.apache.commons.io.FileCleaningTracker
,我很幸运地用自己的实现覆盖了这个类:

/**
 * Cleaning tracker to clean files after each upload with special method invocation.
 * Not thread safe and must be used with 1 factory = 1 thread policy.
 */
public class DeleteFilesOnEndUploadCleaningTracker extends FileCleaningTracker {

     private List<String> filesToDelete = new ArrayList();

     public void deleteTemporaryFiles() {
         for (String file : filesToDelete) {
             new File(file).delete();
         }
         filesToDelete.clear();
     }

     @Override
     public synchronized void exitWhenFinished() {
         deleteTemporaryFiles();
     }

     @Override
     public int getTrackCount() {
         return filesToDelete.size();
     }

     @Override
     public void track(File file, Object marker) {
         filesToDelete.add(file.getAbsolutePath());
     }

     @Override
     public void track(File file, Object marker, FileDeleteStrategy deleteStrategy) {
         filesToDelete.add(file.getAbsolutePath());
     }

     @Override
     public void track(String path, Object marker) {
         filesToDelete.add(path);
     }

     @Override
     public void track(String path, Object marker, FileDeleteStrategy deleteStrategy) {
         filesToDelete.add(path);
     }
 }
在您完成上传项目的工作后,不要忘记调用清理方法:

tracker.deleteTemporaryFiles();
忘了提到:我使用
commons文件上传
version1.2.2和
commons io
version1.3.2

tracker.deleteTemporaryFiles();