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

C++ Discussion :

PDFium memory leaks


Sujet :

C++

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Expert éminent
    Avatar de Paul TOTH
    Homme Profil pro
    Freelance
    Inscrit en
    Novembre 2002
    Messages
    8 964
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 56
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Freelance
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Novembre 2002
    Messages : 8 964
    Par défaut PDFium memory leaks
    Bonjour,

    Je travaille sur une version modifiée de libPDFium qui exploite les derniers sources du projet PDFium...

    et je rencontre un problème que je ne comprend pas, mais comme je ne maîtrise pas C++ je me demande si une explication simple est envisageable.

    si je fais une boucle (sous Delphi mais qu'importe) de LoadLibrary/FreeLibrary sur la DLL sans faire aucun appel d'aucune sorte, j'ai la consommation mémoire de mon process qui augmente petit à petit...j'ai fait le test avec d'ancienne version de la DLL, ou avec une DLL vierge, je n'ai pas ce phénomène. Or la fonction DllMain est vide...alors qu'est ce qui peut bien allouer de la mémoire dans cette boucle ?!

    voici l'occupation mémoire en mode debug sous VC++, chaque itération (j'en fait 1000) prend un peu de mémoire
    Nom : memory.png
Affichages : 266
Taille : 4,5 Ko

    j'ai tenté de remonter les memoryleaks avec un code que j'ai trouvé je ne sais plus où, mais ça ne semble rien faire

    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
    23
    24
    25
     
    #define MEM
    #ifdef MEM
    #define _CRTDBG_MAP_ALLOC
    #include <stdlib.h>
    #include <crtdbg.h>
    #endif
     
     
    BOOL APIENTRY DllMain(HMODULE hModule,
                          DWORD ul_reason_for_call,
                          LPVOID lpReserved) {
      switch (ul_reason_for_call) {
        //case DLL_PROCESS_ATTACH:
        //case DLL_THREAD_ATTACH:
        case DLL_THREAD_DETACH:
        case DLL_PROCESS_DETACH:
    #ifdef MEM
    		_CrtDumpMemoryLeaks();
    #endif
    		break;
      }
      LOG("DLLMAIN\n")
      return TRUE;
    }
    Merci
    Developpez.com: Mes articles, forum FlashPascal
    Entreprise: Execute SARL
    Le Store Excute Store

  2. #2
    Expert éminent
    Avatar de Paul TOTH
    Homme Profil pro
    Freelance
    Inscrit en
    Novembre 2002
    Messages
    8 964
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 56
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Freelance
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Novembre 2002
    Messages : 8 964
    Par défaut
    alors là ! je suis de plus en plus perplexe !

    voici un code C++

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    #include <iostream>
    #include <windows.h>
     
    int main()
    {
    	for (int i = 0; i < 1000; i++) {
    		std::cout << i << "\n";
    		HMODULE h = LoadLibrary(L"libpdfium.dll");
    		FreeLibrary(h);
    	}
        std::cout << "Done\n";
    }
    et la consommation mémoire à l'exécution
    Nom : c++.png
Affichages : 262
Taille : 4,3 Ko
    et voici un code Delphi

    Code Delphi : 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
    program libTestDelphi;
     
    {$APPTYPE CONSOLE}
     
    {$R *.res}
     
    uses
      Winapi.Windows;
     
    var
      i: Integer;
      h: THandle;
    begin
      for i := 0 to 9999 do
      begin
        WriteLn(i);
        h := LoadLibrary('libpdfium.dll');
        FreeLibrary(h);
      end;
      WriteLn('Done');
    end.

    et la consommation mémoire ?!
    Nom : delphi.png
Affichages : 271
Taille : 4,0 Ko

    même résultat avec C++Builder on TCC (Tiny C Compiler)...c'est donc un truc spécifique à VC++ ? ah...ou alors l'allocation étant de base plus grande (13Mb) on ne voit pas le grossissement ?! mais la courbe n'est tout de même pas la même.
    Developpez.com: Mes articles, forum FlashPascal
    Entreprise: Execute SARL
    Le Store Excute Store

  3. #3
    Expert éminent
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 644
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 644
    Par défaut
    Salut,

    Le fait est que je ne comprend pas pourquoi tu t'amuses à charger / libérer la bibliothèque.

    Généralement, l'utilisation d'une dll est de se dire qu'on la charge au début, qu'on la libère à la fin, si bien que, même si tu avais des milliers de pdf à génrer automatiquement, l'idée de base serait d'avoir un code proche de
    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
    int main(){
        /* initialisation: on charge libpdfium */
        HMODULE h = LoadLibrary(L"libpdfium.dll");
        /* exécution du programme */
        generateAllPdfs(/* params */)
        /* finalisation et nettoyage */
        FreeLibrary(h);
    }
    /* avec une fonction de generation des pdf qui pourrait prendre
     * la forme d'une boucle
     */
    void generateAllPdfs(/* params */ ){
        for(int i = 0; i< nombrePdfRequis; ++i){
            /* ... */
        }
    }
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  4. #4
    Expert confirmé
    Homme Profil pro
    Analyste/ Programmeur
    Inscrit en
    Juillet 2013
    Messages
    4 770
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Analyste/ Programmeur

    Informations forums :
    Inscription : Juillet 2013
    Messages : 4 770
    Par défaut
    Citation Envoyé par koala01 Voir le message
    on la charge au début, qu'on la libère à la fin, si bien que, même si tu avais des milliers de pdf à générer automatiquement
    Et on n'a plus qu'à prendre les adresses des fonctions de cette bibliothèque ... ce qui est le principal.

    Ton code et celui de @koala01 ne gère pas les erreurs - effectivement c'est le code qui sera exécuté dans 99% des cas.
    Mais ici il n'y a pas d'erreurs (quoique ), le problème peut venir d'1 problème indépendant du code - je pense à la gestion des "threads" Peut-être qu'avec Delphi, la destruction du "thread" est reportée, peut-être que Visual réutilise le "thread" (il détecte que c'est le même ou il utilise 1 bassin), ...

    Ce genre de micro fuites mémoire, il faut la tester en mode "release" dans 1 environnement de production. En mode "debug" et/ ou avec du code fait en one-shot, ... c'est anecdotique - surtout lorsqu'on touche aux entrailles d'1 bibliothèque (WinAPI qui plus est )

  5. #5
    Expert éminent
    Avatar de Paul TOTH
    Homme Profil pro
    Freelance
    Inscrit en
    Novembre 2002
    Messages
    8 964
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 56
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Freelance
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Novembre 2002
    Messages : 8 964
    Par défaut
    alors, le problème de PDFium c'est qu'il n'est pas threadsafe...l'idée est donc de copier la DLL pour chaque Thread et charger la DLL qui possède un nom différent pour avoir une nouvelle copie du code qui tourne dans son propre Thread.

    ça explique pourquoi il y a plusieurs chargements, par contre je suis bien d'accord avec toi, il ne sert à rien de charger/décharger des 100ènes de fois la DLL, mais dans le code qu'on m'a soumis, la DLL est chargée par le thread, déchargée en fin de traitement et tu peux potentiellement avec des 100ènes de thread qui se suivent au cours du temps.

    ce que j'ai recommandé c'est de réutiliser les DLL chargées, car on n'a jamais des 100ènes de thread qui tournent à un instant T...mais le code de départ aurait du fonctionner sans cette fuite de mémoire que je ne m'explique pas.
    Developpez.com: Mes articles, forum FlashPascal
    Entreprise: Execute SARL
    Le Store Excute Store

  6. #6
    Expert éminent
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 644
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 644
    Par défaut
    Mais, à partir du moment où les choses sont dites et que la bibliothèque n'est pas thread safe, la question est: pourquoi voudrais tu que plusieurs threads n'aillent utiliser cette bibliothèque (sous entendu: en même temps)

    Car, l'un dans l'autre, la génération du pdf sera la toute dernière chose que tu voudras faire, après que toutes les manipulations de données aient été effectuées.

    C'est sur la manipulation de tes données que l'utilisation de threads peut s'avérer utile, histoire que le traitement général des informations n'en vienne pas à demander des heures (ou pour qu'il en demande un peu moins) pour obtenir le résultat souhaité.

    Mais la génération d'un pdf, ce n'est qu'une sauvegarde du résultat dans un format bien spécifique, et il n'y a donc aucune raison de commencer à sauvegarder les données tant... qu'elles sont encore en cours de modification.

    Après, si tu as de nombreux pdf à générer -- parce qu'il n'y a que quelques données qui diffèrent mais que ces différences sont importantes, hé bien... c'est un temps "incompressible", et il est ** peut être ** intéressant d'avoir un (et un seul) thread qui génère les pdf à partir des données qui ne seront plus modifiées, pendant que "d'autres threads" seront occupés à préparer les prochaines données qui devront être enregistrées. Il n'empêche que ce sera toujours un seul et unique thread qui générera l'ensemble des fichiers pdf dont tu as besoin
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

Discussions similaires

  1. Compilation TAO / Mfc : Memory Leaks
    Par Rolsct dans le forum CORBA
    Réponses: 4
    Dernier message: 17/04/2005, 19h13
  2. [MFC] Thread & memory leaks
    Par Racailloux dans le forum MFC
    Réponses: 7
    Dernier message: 15/03/2005, 12h44
  3. Memory leak en C/C++
    Par Roswell dans le forum Autres éditeurs
    Réponses: 6
    Dernier message: 07/07/2004, 19h41
  4. [MFC] A la chasse au memory leak
    Par Yabo dans le forum MFC
    Réponses: 17
    Dernier message: 27/06/2004, 17h35
  5. Réponses: 7
    Dernier message: 26/02/2004, 09h32

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