4 votes

Utiliser finalize() dans mon cas ?

J'ai un ImageWrapper classe qui enregistre les images dans des fichiers temporaires sur le disque afin de libérer la mémoire du tas, et qui permet de les recharger en cas de besoin.

class ImageWrapper {
    File tempFile;
    public ImageWrapper(BufferedImage img) {
        // save image to tempFile and gc()
    }
    public BufferedImage getImage() {
        // read the image from tempFile and return it.
    }
    public void delete() {
        // delete image from disk.
    }
}

Mon problème est de savoir comment s'assurer que les fichiers sont supprimés lorsqu'une telle ImageWrapper L'instance de l'utilisateur est récupérée (sinon je risque de remplir le disque avec des images inutiles). Ce site doit être effectuée pendant que l'application est encore en cours d'exécution (par opposition aux suggestions de nettoyage en cours d'exécution), car elle est susceptible de fonctionner pendant de longues périodes.

Je ne suis pas totalement familier avec le concept GC de Java, et je me demandais si finalize() est ce que je recherche. Mon idée était d'appeler delete() (sur un Thread séparé, d'ailleurs) à partir d'une commande overriden finalize() méthode. Est-ce la bonne façon de procéder ?

UPDATE :

Je ne pense pas que je puisse close() l'objet, comme l'ont suggéré de nombreux utilisateurs, car chacune de ces images est récupérée par une liste de récepteurs que je ne contrôle pas et qui peuvent enregistrer une référence à l'objet. Le seul moment où je suis certain de pouvoir supprimer le fichier est lorsqu'aucune référence n'est conservée, c'est pourquoi j'ai pensé que finalize() est le bon chemin. Des suggestions ?

UPDATE 2 :

Quels sont les scénarios où finalize() ne seront pas appelés ? Si les seules possibilités sont de quitter le programme (d'une manière attendue/imprévue), je peux le supporter, car cela signifie que je risque de ne supprimer qu'un seul fichier temporaire inutile (celui qui a été traité lors de la sortie).

6voto

Brian Agnew Points 143181

Une autre approche consiste à utiliser Fichier.deleteOnExit() qui marque un fichier que la JVM doit supprimer à la sortie. Je réalise que ce n'est pas tout à fait ce que vous recherchez, mais peut être intéressant.

Pour être clair, si votre JVM meurt inopinément, c'est ne le fera pas effacer ces fichiers. Par conséquent, vous pouvez concevoir votre solution de manière à effacer les fichiers de cache. au démarrage afin de ne pas accumuler une masse de fichiers cache inutilisés au fil du temps.

3voto

Java Panter Points 297

Il n'est pas recommandé d'utiliser finalize() Le problème est que vous ne pouvez pas compter sur le ramasseur de déchets pour supprimer un objet. Donc, tout le code que vous mettez dans les surcharges de votre classe finalize() n'est pas garantie.

3voto

jtahlborn Points 32515

Une bonne alternative à finalize est le PhantomReference . la meilleure façon de l'utiliser est :

public class FileReference extends PhantomReference<CachedImage> {
  private final File _file;

  public FileReference(CachedImage img, ReferenceQueue<CachedImage> q, File f) {
    super(img, q);
    _file = f;
  }

  public File getFile() {
    _file;
  }
}

Alors utilise-le comme ça :

public class CachedImage {

    private static final ReferenceQueue<CachedImage> 
            refQue = new ReferenceQueue<CachedImage>();

    static {
        Thread t = new Thread() {
            @Override
            public void run() {
                try {
                    while (true) {
                        FileReference ref = (FileReference)refQue.remove();
                        File f = ref.getFile();
                        f.delete();
                    }
                } catch (Throwable t) {
                    _log.error(t);
                }
            }
        };
        t.setDaemon(true);
        t.start();
    }

    private final FileReference _ref;

    public CachedImage(BufferedImage bi, File tempFile) {
        tempFile.deleteOnExit();
        saveAndFree(bi, tempFile);
        _ref = new FileReference<CachedImage>(this, refQue, tempFile);
    }
    ...
}

2voto

chrylis Points 22655

Il n'y a aucune garantie que votre finalize sera jamais appelée ; en particulier, tous les objets qui traînent à la sortie du programme sont généralement jetés sans nettoyage. Closeable est une bien meilleure option.

0voto

Tom G Points 5727

Comme alternative à la réponse de @Brian Agnew, pourquoi ne pas installer une ShutdownHook qui efface votre répertoire de cache ?

public class CleanCacheOnShutdown extends Thread {
  @Override
  public void run() { ... }
}

System.getRuntime().addShutdownHook(new CleanCacheOnShutdown());

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X