2010-05-13 6 views
1

J'utilise une fonction que j'ai trouvé here pour enregistrer une page Web à la mémoire avec cURL:C++ casté realloc provoquant la fuite de mémoire

struct WebpageData { 
    char *pageData; 
    size_t size; 
}; 

size_t storePage(void *input, size_t size, size_t nmemb, void *output) { 
    size_t realsize = size * nmemb; 

    struct WebpageData *page = (struct WebpageData *)output; 

    page->pageData = (char *)realloc(page->pageData, page->size + realsize + 1); 
    if(page->pageData) { 
     memcpy(&(page->pageData[page->size]), input, realsize); 
     page->size += realsize; 
     page->pageData[page->size] = 0; 
    } 

    return realsize; 
} 

et trouvez la ligne:

page->pageData = (char *)realloc(page->pageData, page->size + realsize + 1); 

est à l'origine une mémoire fuite de quelques centaines d'octets par appel. Le seul vrai changement que j'ai fait de la source originale est de lancer la ligne en question à un (char *), que mon compilateur (gcc, g ++ spécifiquement si c'est un problème ac/C++, mais gcc ne compilerait pas non plus déclaration) insisté sur, mais je suppose que c'est la source de la fuite. Quelqu'un peut-il élucider?

Merci

+0

page-> pageData [page-> size] = 0 nécessaire pour? la taille est stockée quand même. –

Répondre

1

Le code que vous avez posté (autant que je sache) est correct. Si elle fuit, je suppose que vous oubliez free() le bloc de mémoire à un moment donné. realloc est autorisé à créer un nouveau bloc de mémoire entier s'il ne peut pas simplement agrandir le existant, et cela vous intéresse. Il est également possible d'allouer un bloc plus grand que nécessaire, ce qui peut entraîner des fuites fantômes. Maintenant, puisque vous utilisez C++, je dois demander: pourquoi n'utilisez-vous pas std::vector à la place?

struct WebpageData { 
    std::vector<char> pageData; 
    size_t size; 
}; 

size_t storePage(void *input, size_t size, size_t nmemb, void *output) { 
    size_t realsize = size * nmemb; 
    WebpageData *page = reinterpret_cast<WebpageData *>(output); 

    page->pageData.resize(page->size + realsize + 1); 
    memcpy(&(page->pageData[page->size]), input, realsize); 
    page->size += realsize; 
    page->pageData[page->size] = 0; 

    return realsize; 
} 
+0

Merci, les vecteurs ont résolu le problème. Je ne les utilisais pas parce que je construisais ce programme comme un moyen d'apprendre le C++, donc pour le moment je suis plutôt mauvais. Pour référence, devrais-je appeler free() avant chaque appel à storePage? J'utilisais la même instance de WebpageData pour chaque appel. À votre santé. – wyatt

+0

Aussi, quelle est la meilleure façon de convertir un vecteur en une chaîne? Je suppose que le processus itératif que j'ai truqué au jury est plutôt mauvais. – wyatt

+1

@wyatt: Non - non libre à chaque appel, mais à la fin lorsque vous avez terminé avec le bloc de mémoire. La meilleure façon de convertir un vecteur en une chaîne est '& myVector [0]'. –

0

Si le développement sur * nix j'en général essayer d'exécuter le programme avec valgrind (http://valgrind.org/) pour une fuite de mémoire problèmes Realted (dans ce cas, je pense que vous ne savez où la mémoire est affectée, mais où est-il en train d'être libéré?). Dans ce cas, je suggérerais de ne pas utiliser malloc, realloc et toute autre gestion de mémoire c similaire dans un programme C++ à moins que cela ne soit absolument nécessaire et inévitable. Ils devraient être évités en faveur de l'utilisation des outils de gestion de la mémoire C++, dans ce cas je pense que la mémoire n'est pas libérée correctement. L'utilisation de vecteurs C++ vous facilitera probablement la vie car vous n'aurez pas à vous soucier du redimensionnement de la matrice et du suivi de tous les changements dans l'allocation de mémoire.

+0

Je ne crois pas que le problème de l'OP est de * détecter * la fuite de mémoire; c'est trouver la cause de la fuite de mémoire. Valgrind n'est pas bon pour ça si nous avons déjà réduit le problème à cette fonction. Enfin, Valgrind est * nix seulement ce qui pourrait être un problème. Ne pas downvoting - juste en soulignant les problèmes potentiels. –

+0

@Billy ONeal: acclamations, édité le post pour améliorer certains des problèmes que vous avez souligné. – shuttle87

0

La distribution ne doit pas faire de différence avec realloc. Êtes-vous sûr d'avoir une fuite de mémoire? Le code ajoute les données, donc si vous le demandez à stocker trois fois avec 1kB de données à chaque fois, il stockera 3kB. Est-ce ce que vous vouliez quand vous avez copié et collé le code? Et bien sûr vous devez libérer() le bloc quelque part quand vous en avez fini avec.

Autres pensées:

  • sont les mémoire que vous reallocing à l'origine malloc'd ou realloc'd?

  • Notez que si vous ne parvenez pas à réaffecter les données, vous perdrez tout. Si vous réalisez un pointeur temporaire et que vous remplacez simplement page-> pageData si elle est valide, cela ne se produira pas, et vous serez en mesure de signaler l'échec à l'appelant (bien que cela soit très improbable en pratique, et vous aurez probablement beaucoup plus de problèmes si c'est le cas!)

  • Vous réallouez le bloc chaque fois que vous recevez de nouvelles données. Il sera probablement plus efficace d'allouer un bloc plus grand que nécessaire, de récupérer les données dans celui-ci, puis de les réaffecter dans un bloc exact uniquement après avoir reçu toutes les données, de façon à éviter de réallouer le bloc à plusieurs reprises.