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

Macros et VBA Excel Discussion :

"Out of memory" à la fin d'une routine manipulant des "string" importants [XL-2010]


Sujet :

Macros et VBA Excel

  1. #1
    Membre averti
    Inscrit en
    Janvier 2009
    Messages
    21
    Détails du profil
    Informations forums :
    Inscription : Janvier 2009
    Messages : 21
    Par défaut "Out of memory" à la fin d'une routine manipulant des "string" importants
    Bonjour,

    Je rencontre le problème suivant avec l'une de mes routines visant à stocker un fichier en mémoire pour effectuer diverses opérations dessus.

    Le fichier en question pèse environ 500Mo avec quelques 12 000 lignes.

    La routine s'effectue sans problèmes, le fichier est stocké dans une variable puis découpé par ligne dans un tableau. j'arrive à afficher les éléments de ce tableau.

    Seulement, au moment de quitter la routine (avant (ou après?) le end sub) j'obtiens plusieurs fois le message "out of memory".

    voici la fonction pour charger le fichier dans une variable "string":

    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
    26
    27
    28
    29
    30
    Function ReadFileToBuffer(ByVal szFileName As String, _
                                     ByRef errCode As Integer, _
                                     ByRef errString As String) As String
        Dim f As Integer
        Dim buffer As String
     
        ' trappe les erreurs
        On Error GoTo ReadFileToBuffer_ERR
     
        ' Ouverture du fichier en 'Binary'
        f = FreeFile
     
        Open szFileName For Binary As #f
    '        ' préallocation d'un buffer à la taille du fichier
              buffer = Space$(LOF(f))
    '        ' lecture complète du fichier
              Get #f, , buffer
        Close #f
        ReadFileToBuffer = buffer
     
    ReadFileToBuffer_END:
        Exit Function
     
    ReadFileToBuffer_ERR:
        ' Gestion d'erreur
        ReadFileToBuffer = ""
        errCode = Err.number
        errString = Err.Description
        Resume ReadFileToBuffer_END
    End Function
    J'utilise ensuite cette fonction dans le code suivant:

    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
    Sub LoadResultFile()
     
    'declaration
    Dim fileName As String
    Dim Results() As String, tempResult As String
    Dim errCode As Integer, errString As String
     
     
    'get filename and store it
    fileName = pickUpFilename("Results", "*.dat;*.txt")             'simple fonction pour récupérer le chemin complet du fichier
    tempResult = ReadFileToBuffer(fileName, errCode, errString)
    If errCode = 0 Then
        Results = Split(tempResult, vbCrLf)
        MsgBox Results(0)    'cette commande passe sans soucis!!!
        MsgBox Ubound(Results)        'renvoie bien 12000
    Else
        MsgBox "Problem in reading file!" & vbCrLf & "error " & errCode & ": " & errString, vbCritical
    End If
     
    End Sub

    Avez-vous une idée concernant les causes de l'erreur (à priori, il n'y a pas de soucis pour charger l'ensemble en mémoire, mais plutôt au moment de la libération de mémoire faites par le compilo)?
    Si oui, savez-vous comment y remédier?

    Merci de m'avoir lu.

  2. #2
    Expert confirmé

    Homme Profil pro
    Curieux
    Inscrit en
    Juillet 2012
    Messages
    5 169
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Curieux
    Secteur : Arts - Culture

    Informations forums :
    Inscription : Juillet 2012
    Messages : 5 169
    Billets dans le blog
    5
    Par défaut
    Bonjour

    et en essayant de vider les variables juste avant le End Sub ?

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    Erase Results
    tempResult= ""

  3. #3
    Expert confirmé
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Mai 2013
    Messages
    3 609
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Canada

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Alimentation

    Informations forums :
    Inscription : Mai 2013
    Messages : 3 609
    Par défaut
    J'allais répondre la même chose que joe.levrai

    Une question que je me pose, c'est 12000 lignes pour 500 Mo
    Ça me paraît gros pas mal... Je me demande bien ce que peuvent contenir ces lignes... (?)

  4. #4
    Membre averti
    Inscrit en
    Janvier 2009
    Messages
    21
    Détails du profil
    Informations forums :
    Inscription : Janvier 2009
    Messages : 21
    Par défaut
    Aucune amélioration en vidant les variables.

    Les lignes comptent chacune 42000 caractères! (et je n'y suis pour rien )

  5. #5
    Expert confirmé

    Homme Profil pro
    Curieux
    Inscrit en
    Juillet 2012
    Messages
    5 169
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Curieux
    Secteur : Arts - Culture

    Informations forums :
    Inscription : Juillet 2012
    Messages : 5 169
    Billets dans le blog
    5
    Par défaut
    et en vidant buffer et f dans ta fonction ?

  6. #6
    Membre averti
    Inscrit en
    Janvier 2009
    Messages
    21
    Détails du profil
    Informations forums :
    Inscription : Janvier 2009
    Messages : 21
    Par défaut
    f est un entier (2 octets). et le fichier est bien fermé par la commande close

    avec:

    aucun changement. Logiquement buffer est déclarée dans la fonction, donc normalement détruite en sortie de fonction et pas de message à ce moment là.

  7. #7
    Expert confirmé

    Homme Profil pro
    Curieux
    Inscrit en
    Juillet 2012
    Messages
    5 169
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Curieux
    Secteur : Arts - Culture

    Informations forums :
    Inscription : Juillet 2012
    Messages : 5 169
    Billets dans le blog
    5
    Par défaut
    Dans ce cas, il faudrait peut être non montrer ce que tu fais exactement avec des lignes chargées dans ton tableau ?

    ça évitera nos propositions inappropriées (et d'autres exemples comme le vidage du presse-papier si tu ne l'utilises pas etc...)

  8. #8
    Membre averti
    Inscrit en
    Janvier 2009
    Messages
    21
    Détails du profil
    Informations forums :
    Inscription : Janvier 2009
    Messages : 21
    Par défaut
    Le code tel que présenté dans mon premier message provoque le message "out of memory".

    Le fichier chargé en mémoire est un tableau de 12000 lignes et 2000 colonnes séparées par des tabulations.

  9. #9
    Inactif  

    Homme Profil pro
    Développeur .NET
    Inscrit en
    Janvier 2012
    Messages
    4 903
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 69
    Localisation : Canada

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : Finance

    Informations forums :
    Inscription : Janvier 2012
    Messages : 4 903
    Billets dans le blog
    36
    Par défaut
    Bonjour,

    L'utilisation du type string oblige d'utiliser de nombreuses copies de chaînes de caractères qui augmentent les besoins de mémoire vive. Ces besoins s'ajoutent à l'obligation de maintenir le classeur complet en mémoire vive. Excel est fait comme cela, il a constamment besoin de tout le classeur en mémoire vive pour "travailler".

    Il suffit qu'il y ait un autre programme trop agressif fasse concurrence à Excel pour avoir de la mémoire pour que Windows fasse planter Excel.

    Si tu veux rester en VBA, tu pourrais envisager de traiter ton fichier avec ADO. En faisant les requêtes appropriées, tu ne serais peut-être pas obligé de traiter tout le fichier d'un seul coup.

    Ce que tu pourrais aussi faire, c'est de télécharger Visual Studio Community. C'est gratuit et cela permet de créer des compléments COM, dans la lignée des contrôles ActiveX, donc des routines compilés. Ce n'est pas tant pour les dll compilées au lieu de macros VBA interprétées, mais parce que le Framework.net fournit la classe StringBuilder. C'est comme la classe string, sauf qu'elle est moins gourmande en mémoire. Les opérations s'effectuent dans une mémoire tampon, mais au lieu d'être copiés à droite et à gauche, les caractères sont tout simplement remplacés au fur et à mesure des besoins.

  10. #10
    Invité
    Invité(e)
    Par défaut
    Bonjour,
    Tu affectes à une variable temp le contenu d'un fichier de 500mo
    Tu affectes à une autre variables le split du temp 500mo.
    Que veux tu récupérer le ubound ou la variable splite ou le temp!

    Tu peux faire ubound(split .

    Tu déclarer ton temps. Variant temp=split (temp!

    Et utulise doevents avant de sortir de ta sub

    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
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    Function ReadFileToBuffer(ByVal szFileName As String, _
                                     ByRef errCode As Integer, _
                                     ByRef errString As String) As String
        Dim f As Integer
        ' trappe les erreurs
        On Error GoTo ReadFileToBuffer_ERR
     
        ' Ouverture du fichier en 'Binary'
        f = FreeFile
     
        Open szFileName For Binary As #f
    '        ' préallocation d'un buffer à la taille du fichier
              ReadFileToBuffer = Space$(LOF(f))
    '        ' lecture complète du fichier
              Get #f, , ReadFileToBuffer
        Close #f
    DoEvents
        Exit Function
     
    ReadFileToBuffer_ERR:
        ' Gestion d'erreur
        ReadFileToBuffer = ""
        errCode = Err.Number
        errString = Err.Description
        Err.Clear
        ReadFileToBuffer = ""
    DoEvents
    End Function
     
    Sub LoadResultFile()
     
    'declaration
    Dim fileName As String
    Dim Results() As String, tempResult As String
    Dim errCode As Integer, errString As String
     
     
    'get filename and store it
    fileName = pickUpFilename("Results", "*.dat;*.txt")             'simple fonction pour récupérer le chemin complet du fichier
    tempResult = ReadFileToBuffer(fileName, errCode, errString)
    If errCode = 0 Then
         MsgBox Split(tempResult, vbCrLf)(0)     'cette commande passe sans soucis!!!
        MsgBox UBound(Split(tempResult, vbCrLf))         'renvoie bien 12000
    Else
        MsgBox "Problem in reading file!" & vbCrLf & "error " & errCode & ": " & errString, vbCritical
    End If
     DoEvents
    End Sub
    Dernière modification par Invité ; 21/05/2015 à 09h06.

  11. #11
    Membre averti
    Inscrit en
    Janvier 2009
    Messages
    21
    Détails du profil
    Informations forums :
    Inscription : Janvier 2009
    Messages : 21
    Par défaut
    Bonjour,

    Merci pour toutes les réponses. Effectivement, j'avais plusieurs feuilles excel ouvertes, dont 2 particulièrement volumineuses. Si elles sont stockées entièrement en mémoire, ça ne me laisse plus beaucoup de marges. La macro tourne sans soucis lorsqu'aucune feuille volumineuse (200Mo) n'est ouverte

    Après, ça ne m'explique pas pourquoi le message n'arrivait qu’après avoir réalisé l'ensemble des instructions (et donc après avoir parfaitement bien stocké les variables?).

    @rdurupt: merci d'avoir passer du temps sur le problème. J'avoue que la gestion mémoire n'est pas toujours claire en VBA. Parfois il fait une deep copie, et parfois il créé juste des pointeurs sur le même espace mémoire. j'y penserais une prochaine fois, si le problème se représente. Mais en général je préfère éviter l'utilisation des Variant pour m'assurer que je manipule bien ce que je suis sensé manipuler (et puis j'ai un certain nombre de fonction qui ont pour argument des tableaux de string --> type mismatch)

    J'avoue ne pas vraiment comprendre ce que fait le "DoEvents" et son intérêt vis à vis de mon problème.

  12. #12
    Invité
    Invité(e)
    Par défaut
    si tu gère la libération de la mémoire en passant tes variables à vide ou à Nothing, c'est Windows qui gère la mémoire. il faut lui rendre la mains pour lui permettre de bosser! c'est le rôle de doevents!

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Réponses: 7
    Dernier message: 21/10/2010, 13h30
  2. [C++] [gcc] out of memory
    Par fxp17 dans le forum GCC
    Réponses: 5
    Dernier message: 06/01/2006, 10h29
  3. [pb mémoire] out of memory d'eclipse
    Par Casp dans le forum Eclipse Java
    Réponses: 2
    Dernier message: 12/05/2005, 16h39
  4. Out of memory
    Par shurato dans le forum ANT
    Réponses: 1
    Dernier message: 10/11/2004, 16h19
  5. [JBuilder 8] Out of memory problem ...
    Par keros dans le forum JBuilder
    Réponses: 2
    Dernier message: 08/09/2003, 19h03

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