Valgrind是一个优秀的内存调试器,它的选项是–trace-malloc = yes,它产生如下所示的内容:
--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
有没有一个工具来解析这个输出,并告诉我每个地址是否没有正确分配和释放匹配的一对?
GCC与mtrace()函数和mtrace命令行工具类似,但格式不同.
奖金问题:是否可以在“绝对丢失”语句旁边输出实际地址?
(我将这个“C”和“C”标记为最有可能与Valgrind一起使用的两种语言.)
解决方法
昨天的解决方案使用perl来分析输出.显然,作为C程序员,我应该在C中做.我以前没有使用std :: regex,需要先了解一下.所以这里是一个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(),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& 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\\((.*),(.*)\\)) = (.*)"),results[4],::to_long(results[2]) * ::to_long(results[3])); }); exps.emplace_back(re::regex(".*(realloc\\((.*),results[1]); ::insert(m,::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"; } }
因为gcc的当前版本的std :: regex似乎是错误的,所以我使用了Boost的实现.应该很容易切换版本:只需将re定义为std的别名,而不是boost.