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

SL & STL C++ Discussion :

manipulation de std::vector probleme memoire


Sujet :

SL & STL C++

  1. #1
    Membre régulier
    Profil pro
    Inscrit en
    Juillet 2006
    Messages
    11
    Détails du profil
    Informations personnelles :
    Localisation : Suisse

    Informations forums :
    Inscription : Juillet 2006
    Messages : 11
    Par défaut manipulation de std::vector probleme memoire
    Bonjour a tous!

    Je suis confronte a de serieux problemes avec la manipulation des std::vector en c++ avec Visual .Net 2003. J' ai developpe un algorithme qui doit gerer des listes d objets assez complexes j utilise donc des vector pour les stocker.

    Jusque la pas trop de probleme mais par la suite j ai tente d integrer mon algorithme a un autre projet que j ai adapte et les methodes communiquent par le biais de std::vector< std::vector<int> > de maniere iterative. Mais mon programme fini par s arreter pour cause de probleme de memoire de ce type:

    Microsoft C++ exception: std::bad_alloc @ 0x0012ecac.
    Y a t-il un probleme connu avec le fait d envoyer d envoyer en parametres des pointeurs sur des std::vector et de retourner des objets de type std::vector par le biais de methodes d'objet ou de methode statique.

    Voici un exemple de code contenue dans une methode appele de facon iterative:

    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
            std::vector<int> mvRef;
    	int num4x4Blocks = width/4*height/4;
    	blocks4x4.reserve(num4x4Blocks);
    	mvRef.reserve(2*num4x4Blocks);
     
            //
            //
            // Insertion des valeurs dans mvRef a l'aide de differentes
            // methodes
            //
            //
     
     
            return mvRef;    // Ceci cree une erreur de type memory a la 2 eme
                                  // iteration
    Notez qu'il suffit de modifier un bout de code pour que l erreur apparaissent dans une autre methode qui a le meme genre de procede



    Toutes vos suggestions sont les bienvenues...

  2. #2
    Rédacteur
    Avatar de Laurent Gomila
    Profil pro
    Développeur informatique
    Inscrit en
    Avril 2003
    Messages
    10 651
    Détails du profil
    Informations personnelles :
    Âge : 40
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Avril 2003
    Messages : 10 651
    Par défaut
    Que vaut num4x4Blocks avant le plantage ?

  3. #3
    Membre chevronné
    Profil pro
    Inscrit en
    Juillet 2006
    Messages
    258
    Détails du profil
    Informations personnelles :
    Âge : 46
    Localisation : France, Bas Rhin (Alsace)

    Informations forums :
    Inscription : Juillet 2006
    Messages : 258
    Par défaut
    Citation Envoyé par angediablo

    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
            std::vector<int> mvRef;
    	int num4x4Blocks = width/4*height/4;
    	blocks4x4.reserve(num4x4Blocks);
    	mvRef.reserve(2*num4x4Blocks);
     
            //
            //
            // Insertion des valeurs dans mvRef a l'aide de differentes
            // methodes
            //
            //
     
     
            return mvRef;    // Ceci cree une erreur de type memory a la 2 eme
                                  // iteration
    Quelles sont ces "differentes méthodes" ?

    Si ce n'est que des méthodes d'insertion (type push_back) pas de problème. Si tu essaye d'accéder directement à un élément, il peut y avoir problème : reserve n'initialise pas les éléments supplémentaires, il ne change que la capacité du vecteur et pas sa taille.

  4. #4
    Membre régulier
    Profil pro
    Inscrit en
    Juillet 2006
    Messages
    11
    Détails du profil
    Informations personnelles :
    Localisation : Suisse

    Informations forums :
    Inscription : Juillet 2006
    Messages : 11
    Par défaut
    num4x4Blocks est une variable qui ne change jamais apres l'affectation precisee elle vaut 12'288.

    Et seul un push back est effectue sur mvRef. De cette facon:

    for (int i=0; i<num4x4Blocks; i++)
    {
    int v0 = blocks4x4[i]->motionVector[0];
    int v1 = blocks4x4[i]->motionVector[1];
    mvRef.push_back(v0);
    mvRef.push_back(v1);
    }

    // ou blocks4x4 est un sdt::vector<Block> , Block est une classe de mon
    // programme qui possede differentes instances dont int[2] motionVector

    Mais je precise que ce n est qu a une certaine iteration que l appelle a

    return mvRef;

    engendre une erreur de memoire

  5. #5
    Membre expérimenté
    Profil pro
    Inscrit en
    Janvier 2004
    Messages
    192
    Détails du profil
    Informations personnelles :
    Âge : 43
    Localisation : France

    Informations forums :
    Inscription : Janvier 2004
    Messages : 192
    Par défaut
    De quelle taille est chaque objet Block ? Si tu en crées 12288 avec 100Ko chacun, tu atteinds plus d'1Go de mémoire... Si une copie de mvRef est faite en quittant la procédure avant que blocks4x4 soit désalloué, c'est peut-être la goutte d'eau qui fait déborder le vase ? Les Block sont-ils correctement désalloués après la première itération ?

  6. #6
    Membre régulier
    Profil pro
    Inscrit en
    Juillet 2006
    Messages
    11
    Détails du profil
    Informations personnelles :
    Localisation : Suisse

    Informations forums :
    Inscription : Juillet 2006
    Messages : 11
    Par défaut
    Oui avant de retourner mvRef j effectue un blocks4x4.clear() qui vide le vecteur d'objet de type Block, et par la meme occasion desalloue la memoire reservee pour blocks4x4 n'est-ce pas?

  7. #7
    Rédacteur
    Avatar de Laurent Gomila
    Profil pro
    Développeur informatique
    Inscrit en
    Avril 2003
    Messages
    10 651
    Détails du profil
    Informations personnelles :
    Âge : 40
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Avril 2003
    Messages : 10 651
    Par défaut
    Citation Envoyé par angediablo
    Oui avant de retourner mvRef j effectue un blocks4x4.clear() qui vide le vecteur d'objet de type Block, et par la meme occasion desalloue la memoire reservee pour blocks4x4 n'est-ce pas?
    Non, la mémoire est toujours allouée. Mais ça ne devrait pas poser plus de problème que ça.

    Au cas où, si tu veux vraiment essayer de vider physiquement ton tableau, tu peux utiliser ce code à la place du clear() :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    sdt::vector<Block>().Swap(blocks4x4);
    Tu peux aussi tenter d'utiliser un std::deque, qui a la même interface publique que std::vector mais qui est moins contraint au niveau de l'allocation mémoire.

  8. #8
    Membre régulier
    Profil pro
    Inscrit en
    Juillet 2006
    Messages
    11
    Détails du profil
    Informations personnelles :
    Localisation : Suisse

    Informations forums :
    Inscription : Juillet 2006
    Messages : 11
    Par défaut
    Ok et bien il parait que l'appel a clear() vide le vecteur mais ne supprime pas les objets contenus a l interieur lorsque ces derniers sont des pointeurs comme dans mon cas. J'ai donc supprime les pointeur avec un delete mais le meme probleme est apparu a la meme iteration lors d un appel a new voici les details:

    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
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
     
     
    std::vector<int> Multigrid::methodeMultigrid16x16(unsigned char* I_Y,      unsigned char* P_Y, unsigned char* prediction, unsigned char* predictionBlocks, unsigned char* blocksMap, int step, int width,int height, int precision, unsigned int* complexity, unsigned char* prediction4x4)
    {
    	int num128x128Blocks = width/128*height/128;
     
    	int numLevels = log10(double(128/(precision)))/log10(2.0)+1;
     
    	int maxNumBlocks = num128x128Blocks;
     
    	int add = num128x128Blocks;
     
    	for (int i=0; i<numLevels-1; i++)
    	{
    		add = 4*add;
    		maxNumBlocks = maxNumBlocks + add;
    	}
    	int count=0;
     
    	std::vector<Block*> blocks;
    	blocks.reserve(maxNumBlocks);
     
    	for (int i=0; i<maxNumBlocks; i++)
    	{
    		Block* block = new Block(); //------->ENDROIT DU CRASH
    		blocks.push_back(block);
    	}
     
     
     
    	Block::process(I_Y, P_Y, &count, step, width, height, &numLevels, complexity, blocks);
     
    	// Block vector for mapping
    	std::vector<Block*> blocks4x4;
     
    	std::vector<int> mvRef;
    	int num4x4Blocks = width/4*height/4;
    	blocks4x4.reserve(num4x4Blocks);
    	mvRef.reserve(2*num4x4Blocks);
     
    	for (int i=0; i<num4x4Blocks; i++)
    	{
    		Block* block = new Block();
    		blocks4x4.push_back(block);
    	}
     
    	//Mapping multigrid Blocks to 4x4 blocks
    	Block::mappingBlocks4x4(&count,blocks4x4, blocks);
    	Multigrid::constructMultigridPrediction(I_Y, prediction,count, predictionBlocks, blocksMap,blocks);
    	Multigrid::constructPrediction4x4(I_Y, prediction4x4, num4x4Blocks, blocks4x4);
     
    	for ( std::vector<Block*>::iterator it = blocks.begin() ; it != blocks.end(); ++it) 
    	{
    			delete *it;
    	}
     
    	blocks.clear();
     
     
    	//Inserting motion vectors in the motion Vector list
     
    	for (int i=0; i<num4x4Blocks; i++)
    	{
    		int v0 = blocks4x4[i]->motionVector[0];
    		int v1 = blocks4x4[i]->motionVector[1];
    		mvRef.push_back(v0);
    		mvRef.push_back(v1);
    	}
     
     
     
    	for ( std::vector<Block*>::iterator it = blocks4x4.begin() ; it != blocks4x4.end(); ++it) 
    	{
    			delete *it;
    	}
     
     
     
    	blocks4x4.clear();
     
     
     
    	return mvRef;
     
     
    }
    Ainsi que les derniers call stack du mode debug:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
     
     	kernel32.dll!7c81eb33() 	
     	kernel32.dll!7c81eb33() 	
     	msvcr71d.dll!_nh_malloc_dbg(unsigned int nSize=1, int nhFlag=3, int nBlockUse=1240264, const char * szFileName=0x0012ee50, int nLine=1240724)  Line 267 + 0x7	C
     	msvcr71d.dll!_CxxThrowException(void * pExceptionObject=0x0012ece4, const _s__ThrowInfo * pThrowInfo=0x104f6150)  + 0x39	C++
     	msvcp71d.dll!std::_Nomemory()  Line 10	C++
    >	H264AVCEncoderLibTestStaticd.exe!operator new(unsigned int size=60)  Line 15	C++
     	H264AVCEncoderLibTestStaticd.exe!Multigrid::methodeMultigrid16x16(unsigned char * I_Y=0x06e89ff8, unsigned char * P_Y=0x04d7e028, unsigned char * prediction=0x06eba038, unsigned char * predictionBlocks=0x06eea078, unsigned char * blocksMap=0x06f1a0b8, int step=16, int width=512, int height=384, int precision=4, unsigned int * complexity=0x0012eee4, unsigned char * prediction4x4=0x06f4a0f8)  Line 84 + 0x7	C++
    Et l'endroit ou le programme crash suite a l'appel a new():
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
     
    void *__cdecl operator new(size_t size) _THROW1(_STD bad_alloc)
    	{	// try to allocate size bytes
    	void *p;
    	while ((p = malloc(size)) == 0)
    		if (_callnewh(size) == 0)
    			_STD _Nomemory();
    	return (p); //--------------> ENDROIT DU CRASH!!!!!!!!!!!!
    	}

  9. #9
    Rédacteur
    Avatar de Laurent Gomila
    Profil pro
    Développeur informatique
    Inscrit en
    Avril 2003
    Messages
    10 651
    Détails du profil
    Informations personnelles :
    Âge : 40
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Avril 2003
    Messages : 10 651
    Par défaut
    Ok et bien il parait que l'appel a clear() vide le vecteur mais ne supprime pas les objets contenus a l interieur lorsque ces derniers sont des pointeurs comme dans mon cas
    Oui, il n'est pas censé savoir que tu stockes des variables que tu as allouées avec new... Il vide la mémoire qu'il alloue lui-même, ce qui n'est déjà pas mal.
    Bref il faut bien que tu libères ce que tu alloues avec new. D'ailleurs ces allocations sont-elles nécessaires ?

  10. #10
    Rédacteur

    Avatar de Matthieu Brucher
    Profil pro
    Développeur HPC
    Inscrit en
    Juillet 2005
    Messages
    9 810
    Détails du profil
    Informations personnelles :
    Âge : 43
    Localisation : France, Pyrénées Atlantiques (Aquitaine)

    Informations professionnelles :
    Activité : Développeur HPC
    Secteur : Industrie

    Informations forums :
    Inscription : Juillet 2005
    Messages : 9 810
    Par défaut
    Si ça plante sur le new Block, c'est une erreur dans le constructeur.

  11. #11
    Rédacteur
    Avatar de Laurent Gomila
    Profil pro
    Développeur informatique
    Inscrit en
    Avril 2003
    Messages
    10 651
    Détails du profil
    Informations personnelles :
    Âge : 40
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Avril 2003
    Messages : 10 651
    Par défaut
    Citation Envoyé par Miles
    Si ça plante sur le new Block, c'est une erreur dans le constructeur.
    Hum... Si ça renvoie un bad_alloc et que le debugger s'arrête dans la définition de l'opérateur new, alors ça peut difficilement être le constructeur de l'objet qui a levé une exception

    C'est l'allocation de mémoire qui a échoué, et c'est certainement dû à la gestion approximative de celle-ci.

  12. #12
    Membre régulier
    Profil pro
    Inscrit en
    Juillet 2006
    Messages
    11
    Détails du profil
    Informations personnelles :
    Localisation : Suisse

    Informations forums :
    Inscription : Juillet 2006
    Messages : 11
    Par défaut
    Ca je veux bien te croire. Plus habitue au language Java, je suis plutot nouvel utilisateur du language c++ et donc pas habitue a devoir gerer la memoire. Et effectivement ce n est pas le constructeur qui leve l exception no_memory

  13. #13
    Rédacteur

    Avatar de Matthieu Brucher
    Profil pro
    Développeur HPC
    Inscrit en
    Juillet 2005
    Messages
    9 810
    Détails du profil
    Informations personnelles :
    Âge : 43
    Localisation : France, Pyrénées Atlantiques (Aquitaine)

    Informations professionnelles :
    Activité : Développeur HPC
    Secteur : Industrie

    Informations forums :
    Inscription : Juillet 2005
    Messages : 9 810
    Par défaut
    C'est vrai... Quel est le niveau d'occupation mémoire global ? Est-ce qu'il y a des allocations mémoire dans le constructeur ? Avec un fonctionnement pas à pas, qui lève l'exception ?

  14. #14
    Membre régulier
    Profil pro
    Inscrit en
    Juillet 2006
    Messages
    11
    Détails du profil
    Informations personnelles :
    Localisation : Suisse

    Informations forums :
    Inscription : Juillet 2006
    Messages : 11
    Par défaut
    Le niveau d occupation memoire n est que de 67M environ avant le crash.
    Et non il n'y a pas d allocution memoire de type new() dans le constructeur

  15. #15
    Membre régulier
    Profil pro
    Inscrit en
    Juillet 2006
    Messages
    11
    Détails du profil
    Informations personnelles :
    Localisation : Suisse

    Informations forums :
    Inscription : Juillet 2006
    Messages : 11
    Par défaut
    Comme ecrit precedemment l'exception est levee par l'operateur new
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
     
     
    void *__cdecl operator new(size_t size) _THROW1(_STD bad_alloc)
    	{	// try to allocate size bytes
    	void *p;
    	while ((p = malloc(size)) == 0)
    		if (_callnewh(size) == 0)
    			_STD _Nomemory();
    	return (p);
    	}
    ou size vaut 60 lors du crash. Durant la boucle _STD _Nomemory() est atteint

  16. #16
    Rédacteur

    Avatar de Matthieu Brucher
    Profil pro
    Développeur HPC
    Inscrit en
    Juillet 2005
    Messages
    9 810
    Détails du profil
    Informations personnelles :
    Âge : 43
    Localisation : France, Pyrénées Atlantiques (Aquitaine)

    Informations professionnelles :
    Activité : Développeur HPC
    Secteur : Industrie

    Informations forums :
    Inscription : Juillet 2005
    Messages : 9 810
    Par défaut
    Très très bizarre...

  17. #17
    Membre régulier
    Profil pro
    Inscrit en
    Juillet 2006
    Messages
    11
    Détails du profil
    Informations personnelles :
    Localisation : Suisse

    Informations forums :
    Inscription : Juillet 2006
    Messages : 11
    Par défaut
    J'ai modifier mon code en ne passant que des references cette fois-ci et non pas des copies de vecteurs comme je le faisait avant mais l erreur de memoire est revenue au niveau du

    return mvRef;

    mais a la 1ere iteration cette fois ci. C est a ni rien comprendre!!!!!!!

  18. #18
    Rédacteur/Modérateur
    Avatar de JolyLoic
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2004
    Messages
    5 463
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 50
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Août 2004
    Messages : 5 463
    Par défaut
    Une question : Comment as-tu mesuré l'occupation mémoire ?
    Ma session aux Microsoft TechDays 2013 : Développer en natif avec C++11.
    Celle des Microsoft TechDays 2014 : Bonnes pratiques pour apprivoiser le C++11 avec Visual C++
    Et celle des Microsoft TechDays 2015 : Visual C++ 2015 : voyage à la découverte d'un nouveau monde
    Je donne des formations au C++ en entreprise, n'hésitez pas à me contacter.

  19. #19
    Membre régulier
    Profil pro
    Inscrit en
    Juillet 2006
    Messages
    11
    Détails du profil
    Informations personnelles :
    Localisation : Suisse

    Informations forums :
    Inscription : Juillet 2006
    Messages : 11
    Par défaut
    j ai juste regardé la valeur indiquée dans le gestionnaire de tâches

  20. #20
    Membre régulier
    Profil pro
    Inscrit en
    Juillet 2006
    Messages
    11
    Détails du profil
    Informations personnelles :
    Localisation : Suisse

    Informations forums :
    Inscription : Juillet 2006
    Messages : 11
    Par défaut
    Finalement je me suis resigne a utilier un tableau de pointeurs a la place des vecteurs car meme n utilisant que du referencement ( c est a dire en ne transmettant jamais une copie d un objet envoye en parametre a une methode mais plutot la reference de ce dernier) et ca plante moins facilement. Mais comme mon programme est engage dans un boucle qui devrais selon les cas atteindre jusqu a un maximum de 1000 iterations environ, Je fini tout de meme par avoir un runtime error et mon programme se voit forcer d etre interrompu par le system. Pourtant ma contribution n est qu un plug in a un soft qui tourne deja sans aucun probleme meme avec plus de 1000 iteration. Je sais que la coquille vient de mon bout de code mais ou exactement? aucune idee. Je crois avoir tout essaye. Cependant j ai remarque un phenomene bizarre: lorsque la reference a **blocks est envoye en paremetre (&blocks) a une methode qui ne fait que de lire les valeurs pointee sans en modifier aucune elles sont alteree des la fin de l execution de la methode. D'ou peut venir ce genre de phenomenes en general?

Discussions similaires

  1. Probleme avec std::vector push_back
    Par raphchar dans le forum C++
    Réponses: 4
    Dernier message: 19/12/2011, 14h18
  2. [STL] déclaration et manipulation de std::vector
    Par archer dans le forum SL & STL
    Réponses: 3
    Dernier message: 04/11/2007, 21h56
  3. Probleme avec std::vector
    Par dhoorens dans le forum SL & STL
    Réponses: 2
    Dernier message: 12/03/2007, 16h51
  4. Problem avec std::vector
    Par boiteweb dans le forum SL & STL
    Réponses: 5
    Dernier message: 29/04/2006, 12h56
  5. [std::vector] probleme de desallocation memoire
    Par jcloupgarou dans le forum SL & STL
    Réponses: 15
    Dernier message: 20/04/2006, 11h39

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