IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Entrée/Sortie Java Discussion :

Dépassement mémoire MappedByteBuffer


Sujet :

Entrée/Sortie Java

  1. #1
    Membre Expert
    Profil pro
    Fabrication GED
    Inscrit en
    Octobre 2005
    Messages
    1 405
    Détails du profil
    Informations personnelles :
    Âge : 46
    Localisation : France, Seine Maritime (Haute Normandie)

    Informations professionnelles :
    Activité : Fabrication GED

    Informations forums :
    Inscription : Octobre 2005
    Messages : 1 405
    Par défaut Dépassement mémoire MappedByteBuffer
    Bonjour à tous.
    Je suis confronté à un problème mémoire lié aux MappedByteBuffer récupérés via java.nio.FileChannels.FileChannel.map(..) :
    J'ai une méthode qui consiste à faire une recherche dans un fichier binaire, et pour cela, à chaque fois qu'elle est appelée :
    - elle crée le FileInputStream, récupère le FileChannel correspondant, et récupère la référence sur le MappedByteBuffer via la méthode "map(...)".
    - elle ferme correctement les flux (FileInputStream et FileChannel) dans le bloc "finally"
    - elle va même dans ce bloc "finally" jusqu'à faite un "clear" du MappedByteBuffer si ce dernier n'est pas nul.

    Mon problème :
    Si j'exécute une à deux fois cette méthode dans mon main (via une boucle), pas de soucis.
    Si je veux l'exécuter une vingtaine de fois, ça plante :
    java.io.IOException: Espace insuffisant pour traiter cette commande
    at sun.nio.ch.FileChannelImpl.map0(Native Method)
    at sun.nio.ch.FileChannelImpl.map(Unknown Source)
    at com.iohack.binarytools.BinaryFile.searchRecords_NIO_MappedMode(BinaryFile.java:87)
    at com.iohack.binarytools.BinaryFile.main(BinaryFile.java:253)

    Je suis étonné de ce comportement, on dirait que le garbage collector ne fait pas son travail de récupération de la mémoire.
    J'ai peut-être un début d'explication : le mapping de nio délègue au système d'exploitation les accès au fichier. Exécutant mon job sous cette saloperie de windows XP, je souspçonne que c'est ce dernier qui ne sait pas gérer la libération mémoire...
    La trace de l'exception étant vraiment simplissime et la javadoc de même : "IOException - If some other I/O error occurs", je me demande quel est l'intérêt d'utiliser une méthode aussi peu fiable alors qu'elle est censée apporter certaines optimisations... Les packages du JDK ne seraient donc plus multi-plateforme ? (j'espère me tromper)...

    Si quelqu'un a une explication et/ou une solution de contournement (vidage explicite de la mémoire) j'en serais fort intéressé

  2. #2
    Membre émérite
    Profil pro
    Inscrit en
    Février 2007
    Messages
    572
    Détails du profil
    Informations personnelles :
    Localisation : France, Ille et Vilaine (Bretagne)

    Informations forums :
    Inscription : Février 2007
    Messages : 572
    Par défaut
    Bonjour,

    En C, la fonction mmap fait une projection en mémoire d'un fichier. Cette projection n'est pas detruite à la fermeture du fichier. Il faut soit appeler explicitement munmap, ou attendre la fin du processus.

    En java, pour map, qui utilise probablement mmap, a priori c'est la meme chose. Tu pourrais faire tous les close que tu veux, le buffer créé ne sera pas libéré. J'ai relu la doc, et seul le gc peut detruire la projection d'un MappedByteBuffer (je n'ai pas vu de methode explicite)

    J'ai fait un test sur des fichiers assez gros (des .avi de films), sous XP, et ca a l'air de marcher (sur une boucle de 100 itérations).

    Est ce que ca pourrait être une probleme de reference sur des MappedByteBuffer ?

  3. #3
    Membre Expert
    Profil pro
    Fabrication GED
    Inscrit en
    Octobre 2005
    Messages
    1 405
    Détails du profil
    Informations personnelles :
    Âge : 46
    Localisation : France, Seine Maritime (Haute Normandie)

    Informations professionnelles :
    Activité : Fabrication GED

    Informations forums :
    Inscription : Octobre 2005
    Messages : 1 405
    Par défaut
    Bonjour
    Merci à toi pour ta réponse.
    Après plusieurs test, j'en conclue que c'est un problème de GargageCollector (jusqu'à ce que l'on me prouve le contraire). Je m'explique :
    - Ce n'est pas un problème de références qui traineraient, vu que le MappedByteBuffer, ainsi que le FileInputStream et FileChannel sont locaux à ma méthode.
    - Même en forçant l'affectation de tous ces objets à "null" en fin de méthode ne résoud pas le problème.
    - Un appel à "System.gc()" en fin de méthode résoud le problème. Je sais qu'appeler cette méthode est mal et pas fiable mais visiblement, je n'ai pas trop le choix pour faire quelque chose de fonctionnel (surtout pas d'autre solution).

    Par contre peux-tu me dire comment tu as testé une boucle de 100 sans problème ? Tu parles de process, tu as utilisé les threads ? parce que mes test étaient basé sur des fichiers de 500Mo environ, et le problème arrivait environ à la 7ème itération.
    Je précise que c'est dans mon "main" que se trouvait la boucle et non pas dans un script qui invoquerait 100 fois "java.exe MaClass".

  4. #4
    Membre émérite
    Profil pro
    Inscrit en
    Février 2007
    Messages
    572
    Détails du profil
    Informations personnelles :
    Localisation : France, Ille et Vilaine (Bretagne)

    Informations forums :
    Inscription : Février 2007
    Messages : 572
    Par défaut
    Citation Envoyé par iohack Voir le message
    Par contre peux-tu me dire comment tu as testé une boucle de 100 sans problème ? Tu parles de process, tu as utilisé les threads ? parce que mes test étaient basé sur des fichiers de 500Mo environ, et le problème arrivait environ à la 7ème itération.
    Je précise que c'est dans mon "main" que se trouvait la boucle et non pas dans un script qui invoquerait 100 fois "java.exe MaClass".
    Je parlais bien de process, et pas de thread. En C, si tu fais un mmap dans un thread, et que le thread meurt, la projection n'est pas détruite. En java, visiblement c'est pareil.

    Je pense que j'ai fait le meme genre de test que toi, i.e une boucle dans le main. Voila mon code, peut être y verras tu une difference majeure.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    public static void main(String[] args) {
     
            try {            
                File file = new File(
                        "D:/Film/Leo Et Popi.avi");
                FileInputStream stream = new FileInputStream(file);
                MappedByteBuffer buffer = null;
     
                FileChannel channel = stream.getChannel();
     
                //ArrayList<MappedByteBuffer> buffers = new ArrayList<MappedByteBuffer>();
                for (int i = 0; i < 100; ++i) {
                    buffer = channel.map(MapMode.READ_ONLY, 0, file.length());
                    System.out.println("Buffer[0]" + buffer.getInt(i));
                    //buffers.add(buffer);
                }
     
            } catch (Exception e) {
                e.printStackTrace();
            }
     
        }
    Le .avi fait environ 790Mo

    Un détail qui a son importance, je suis en version 6.

  5. #5
    Membre Expert
    Profil pro
    Fabrication GED
    Inscrit en
    Octobre 2005
    Messages
    1 405
    Détails du profil
    Informations personnelles :
    Âge : 46
    Localisation : France, Seine Maritime (Haute Normandie)

    Informations professionnelles :
    Activité : Fabrication GED

    Informations forums :
    Inscription : Octobre 2005
    Messages : 1 405
    Par défaut
    Bonjour
    J'ai bien lu ta réponse mais je n'ai pas eu le temps de faire de test cette semaine.
    - Je pensais comme toi pour les threads/process.
    - Cela peut peut-être venir de la version qui est obligatoirement 1.4( Système d'exploitation IBM AIX 5.1). Testerais chez moi avec 1.6...
    - Cela pourrait également venir du fait que mes FileInputStream / FileChannel / MappedByteBuffer sont créés à l'intérieur d'une méthode et que c'est cette méthode qui est appelée plusieurs fois de suite (contrairement à ton exemple où FileInputStream et FileChannel ne sont créés qu'une fois pour la boucle)... Je devrais donc également tester ton exemple...

    Suite au prochain épisode...

    PS : Je trouve cela un peu c.. que la capacité d'un MappedByteBuffer soit exprimé en "int". En int, cela signifie que taille max = Integer.MAX_VALUE soit 2 Go. Sur des machines qui possèdent plusieurs dizaines de Go de RAM, on fait comment pour traiter les fichiers d'une taille supérieure à cette limite ? (réponse : on utilise les méthodes read et write classique et on ne peut pas profiter des optimisations )

    En tout cas, merci d'avoir pris le temps de répondre.

Discussions similaires

  1. Liaison série >> Erreur dépassement mémoire
    Par Arameya dans le forum C++
    Réponses: 0
    Dernier message: 16/05/2011, 12h38
  2. Dépassement mémoire et contrôle utilisateur
    Par bzh_coder dans le forum C#
    Réponses: 2
    Dernier message: 04/05/2010, 10h05
  3. [FPDF] Dépassement mémoire png
    Par benji07 dans le forum Bibliothèques et frameworks
    Réponses: 4
    Dernier message: 03/11/2009, 12h32
  4. HEAP Size et dépassement mémoire
    Par Sentenza28 dans le forum Général Java
    Réponses: 6
    Dernier message: 20/09/2007, 11h33
  5. Analyseur code pour dépassement mémoire
    Par adrienj dans le forum Autres éditeurs
    Réponses: 2
    Dernier message: 13/07/2006, 21h53

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo