Valgrind memory leak with std::string in std::map

2019-05-06 23:06发布

问题:

Here is the output from Valgrind:

==6519==    at 0x4C25885: operator new(unsigned long) (vg_replace_malloc.c:319)
==6519==    by 0x4EE65D8: std::string::_Rep::_S_create(unsigned long, unsigned long, std::allocator<char> const&) (new_allocator.h:104)
==6519==    by 0x4EE7CE0: char* std::string::_S_construct<char const*>(char const*, char const*, std::allocator<char> const&, std::forward_iterator_tag) (basic_string.tcc:138)
==6519==    by 0x4EE80F7: std::basic_string<char, std::char_traits<char>, std::allocator<char> >::basic_string(char const*, std::allocator<char> const&) (basic_string.h:1725)
==6519==    by 0x41C399: pilInpOpts::pilInpOpts() (pilInpOpts.cpp:12)
==6519==    by 0x403A55: main (main.cpp:32)

This same error is repeated for every entry in the map.

main.cpp line 32 is:

    pilInpOpts input;

Line 12 of the pilInpOpts is part of the constructor:

#include "pilInpOpts.h"
#include <iostream>
#include <fstream>
#include <string>
#include <sstream>


pilInpOpts::pilInpOpts() 
{
// create the map of options, put in alphabetical order to ease sorting
piloptmap.insert(std::pair<std::string, bool>("bforce",false));
piloptmap.insert(std::pair<std::string, bool>("coef",false));
piloptmap.insert(std::pair<std::string, bool>("dualjet",false));
piloptmap.insert(std::pair<std::string, bool>("flow",false));
piloptmap.insert(std::pair<std::string, bool>("gforce",false));
piloptmap.insert(std::pair<std::string, bool>("gpress",false));
piloptmap.insert(std::pair<std::string, bool>("matlab",false));
piloptmap.insert(std::pair<std::string, bool>("model",false));
piloptmap.insert(std::pair<std::string, bool>("out_shade",false));
piloptmap.insert(std::pair<std::string, bool>("out_shade_file",false));
piloptmap.insert(std::pair<std::string, bool>("press",false));
piloptmap.insert(std::pair<std::string, bool>("proc",false));
piloptmap.insert(std::pair<std::string, bool>("shade",false));
piloptmap.insert(std::pair<std::string, bool>("summary",false));
piloptmap.insert(std::pair<std::string, bool>("trans",false));
// need to define the default filepaths, this is needed because they are optional
platpath = "";
vehpath = "";
apppath = "";
dockpath = "";
};

I found some posts in SO which said Valgrind may produce false positives. For example: std::string memory leak

Is this a false positive since std::string has all the constructors etc it needs to do this? Or should I change to use C character arrays in the map?

回答1:

One of the probable reasons of this behavior may be memory pooling in C++ standard library implementation.

From Valgrind faq:

Memory for quite a number of destructed objects is not immediately freed and given back to the OS, but kept in the pool(s) for later re-use. The fact that the pools are not freed at the exit of the program cause Valgrind to report this memory as still reachable. The behaviour not to free pools at the exit could be called a bug of the library though.

You can set GLIBCXX_FORCE_NEW environment variable before running your app to force STL to free memory as soon as possible.

See also these links on details of libstdc++ memory allocator implementation:

  • https://gcc.gnu.org/onlinedocs/libstdc++/faq.html#faq.memory_leaks
  • https://gcc.gnu.org/onlinedocs/libstdc++/manual/debug.html#debug.memory


回答2:

I've had similar issues with strings, and if I recall correctly, I was able to get rid of the errors by specifically implementing a destructor for the container class. For a map, you'll need to make an iterator, then explicitly delete the elements of iterator->first and iterator->second inside a loop for the size of the map.