Valgrind est un excellent débogueur de mémoire, et il a l'option - Trace-Malloc = Oui Code>, qui produit quelque chose comme ceci:
--16301-- malloc(8) = 0x4EAD748
--16301-- free(0x4EAD748)
--16301-- free(0x4EAD498)
--16301-- malloc(21) = 0x4EAD780
--16301-- malloc(8) = 0x4EAD838
--16301-- free(0x4EAD6F8)
--16301-- calloc(1,88) = 0x4EAD870
--16301-- realloc(0x0,160)malloc(160) = 0x4EB1CF8
--16301-- realloc(0x4EB9F28,4) = 0x4EBA060
3 Réponses :
La sortie semble être une sortie partielle (ou it d'un code hideusement brisé. Cependant, cela semble être un jobby pour un simple script Perl correspondant à l'adresse. En réalité, avec les expressions régulières de C ++ 2011, même C ++ devrait Soyez à la hauteur de la tâche mais je n'ai pas encore utilisé cela. Donc, voici un script Perl simple (bien que probablement plutôt maladroit), lecture de la sortie de Valgrind à partir d'une entrée standard:
#!/usr/bin/perl -w use strict; my %allocated; while (<>) { chomp; if (/(realloc\(([^,]*),([^)]*)\)).* = (.*)/) { if ($2 ne "0x0") { if (!exists $allocated{$2}) { print "spurious realloc($2, $3) = $4\n"; } else { delete $allocated{$2}; } } $allocated{$4} = "$1$;$3"; } elsif (/(malloc\((.*)\)) = (.*)/) { $allocated{$3} = "$1$;$2"; } elsif (/ free\((.*)\)/) { if ($1 ne "0x0") { if (!exists $allocated{$1}) { print "spurious free($1)\n"; } else { delete $allocated{$1}; } } } elsif (/(calloc\((.*),(.*)\)) = (.*)/) { $allocated{$4} = "$1$;" . ($2 * $3); } } my $total = 0; foreach my $leak (keys %allocated) { my($call, $size) = split(/$;/, $allocated{$leak}); print "leak: address=$leak source=$call size=$size\n"; $total += $size; } if (0 < $total) { print "total leak=$total\n"; }
Oui, la sortie est juste un exemple pour démontrer les lignes possibles! Laissez-moi essayer le script - merci! Oh, pouvez-vous faire ignorer toutes les lignes qui ne correspondent pas au motif?
Très agréable. Une question: ce compte pour les différentes possibilités de realloc code>? Il peut être soit un nouveau nouveau
MALLOC code>, soit il peut déplacer une adresse existante autour. (Aussi,
gratuit (0) code> n'est pas faux :-).)
Désolé d'être un nuisible: pouvez-vous le faire ajouter le montant final fui? Je veux le comparer au rapport propre de Valgrind.
En effet. J'utilise toujours boost :: regex code> pour l'instant; Il a essentiellement la même interface.
La solution d'hier a utilisé Perl pour analyser la sortie. Évidemment, étant un programmeur C ++, je suis censé le faire en C ++. Je n'avais pas utilisé std :: regex code> avant et besoin d'en apprendre un peu de ceci en premier. Voici donc une solution C ++:
#include "boost/regex.hpp"
#include <functional>
#include <iostream>
#include <iterator>
#include <map>
#include <stdexcept>
#include <string>
#include <vector>
namespace re = boost;
long to_long(std::string const& s)
{
return strtol(s.c_str(), 0, 10);
}
template <typename T>
static void insert(T& map, std::string const& address, std::string const& call, size_t size)
{
if (!map.insert(std::make_pair(address, std::make_pair(call, size))).second)
std::cout << "WARNING: duplicate address for " << call << ": " << address << "\n";
}
template <typename T>
static void erase(T& map, std::string const& address, std::string const& call)
{
auto it(map.find(address));
if (it == map.end() && address != "0x0")
std::cout << "WARNING: spurious address in " << call << "\n";
else
map.erase(it);
}
static void process(std::istream& in)
{
std::map<std::string, std::pair<std::string, size_t>> m;
std::vector<std::pair<re::regex, std::function<void(re::smatch&)>>> exps;
exps.emplace_back(re::regex(".*(malloc\\((.*)\\)) = (.*)"), [&](re::smatch& results){
::insert(m, results[3], results[1], ::to_long(results[2]));
});
exps.emplace_back(re::regex(".*(free\\((.*)\\))"), [&](re::smatch& results){
::erase(m, results[2], results[1]);
});
exps.emplace_back(re::regex(".*(calloc\\((.*),(.*)\\)) = (.*)"), [&](re::smatch& results){
::insert(m, results[4], results[1], ::to_long(results[2]) * ::to_long(results[3]));
});
exps.emplace_back(re::regex(".*(realloc\\((.*),(.*)\\)) = (.*)"), [&](re::smatch& results){
::erase(m, results[2], results[1]);
::insert(m, results[4], results[1], ::to_long(results[3]));
});
for (std::string line; std::getline(in, line); )
{
re::smatch results;
for (auto it(exps.begin()), end(exps.end()); it != end; ++it)
{
if (re::regex_match(line, results, it->first))
{
(it->second)(results);
break;
}
}
}
size_t total{0};
for (auto it(m.begin()), end(m.end()); it != end; ++it)
{
std::cout << "leaked memory at " << it->first << " " << "from " << it->second.first << "\n";
total += it->second.second;
}
std::cout << "total leak: " << total << "\n";
}
int main(int, char*[])
{
try
{
::process(std::cin);
}
catch (std::exception const &ex)
{
std::cerr << "ERROR: " << ex.what() << "\n";
}
}
Je suis un peu en retard à la fête, mais l'autre réponse n'a pas pris en compte Memalign. Il existe d'autres fonctions telles que Valloc, Cfree ou Posix_Memalign, mais au moins sur Linux, ils sont aliasés. Quoi qu'il en soit, voici ma version Python, pas de garanties.
#!/usr/bin/python import sys, re memmap = {} for line in sys.stdin: tok = [x for x in re.split(' |\(|\)|,|=|\n', line) if x][1:] if tok and tok[0] in ['malloc', 'calloc', 'memalign', 'realloc', 'free']: addr = int(tok[-1], 16) if tok[0] == 'malloc': memmap[addr] = int(tok[1]) elif tok[0] == 'calloc': memmap[addr] = int(tok[1]) * int(tok[2]) elif tok[0] == 'memalign': memmap[addr] = int(tok[-2]) elif tok[0] == 'realloc': oldaddr = int(tok[1], 16) if oldaddr != 0: del memmap[oldaddr] memmap[addr] = int(tok[2]) elif tok[0] == 'free' and addr != 0: del memmap[addr] for k, v in memmap.iteritems(): print 'leak at 0x%x, %d bytes' % (k, v) print 'total %d bytes' % sum(memmap.itervalues())