views:

108

answers:

4
std::map<int, int> * mp = new std::map<int, int>;
for(int i = 0; i < 999999; i++){
  mp->insert(std::pair<int, int>(i, 999999-i )); 
}
p("created");
//mp->clear();     -     doesn't help either
delete mp;
p("freed");

The problem is: "delete mp" doesn't do anything. To compare:

std::vector<int> * vc = new std::vector<int>;
for(int i = 0; i < 9999999; i++){
  vc->push_back(i); 
}
p("created");
delete vc;
p("freed");

releases memory. How to release memory from map?
PS: p("string") just pauses program and waits for input.

+6  A: 

The RAM used by the application is not a precise way to tell if the memory has been semantically freed.

Freed memory is memory that you can reuse. Sometimes though, you don't observe this freed memory directly in what the OS reports as memory used by our app.

You know that the memory is freed because the semantics of the language say so.

Daniel Daranas
well, if i iterate 99999999 the program will eat up to 15% of my computer RAM (4GB), so i'm not talking about kBytes of RAM. if i use vector, after deleting 15% ram usage will drop to 0.0%. If i use map, i don't see any difference after "delete".
foret
@foret: that's probably because vector<T> must use a single contiguous allocation, whereas std::map<T,U> will use many small allocations (one per key/value node). It's common for allocations > 4KB to be handed off to the OS directly.
MSalters
@foret: To see that in practice, simply put the code into a loop and run it e.g. ten times. In your case no further memory growth should occur after first loop iteration.
Dummy00001
+1  A: 

Actually, if the following code doesn't leak:

{
  std::map<int, int> some_map;
}

The following code shouldn't leak as well:

{
  std::map<int, int>* some_map = new std::map<int, int>();
  /* some instructions that do not throw or exit the function */
  delete some_map;
}

This applies whatever the type you use with new, as long as the type is well written. And std::map is probably very well written.

I suggest you use valgrind to check for your leaks. I highly doubt that what you observed was a real leak.

ereOn
It's more probable that the STL allocation scheme keeps the deallocated memory around for future allocation :)
Matthieu M.
A: 

To pinpoint if you are releasing memory or not, try adding observable effects to the destructors of your object and... observe them. For instance, instead of a map, create a custom class which emits output when the destructor is invoked. Something like this:

#include <map>
#include <iostream>
#include <utility>

class Dtor{
        int counter;
    public:
        explicit Dtor(int c):counter(c) {std::cout << "Constructing counter: " << counter << std::endl; }
        Dtor(const Dtor& d):counter(d.counter) {std::cout << "Copy Constructing counter: " << counter << std::endl; }
        ~Dtor(){ std::cout << "Destroying counter: " << counter << std::endl; }
};

int main(){
    std::map<int, const Dtor&> * mp = new std::map<int, const Dtor&>;
    for (int i = 0; i < 10; ++i){
        mp -> insert(std::make_pair(i, Dtor(i)));
    }
   delete mp;
   return 0;
}

You will witness that deleting the pointer invokes the destructor of your objects, as expected.

Francesco
If you are doing this it is often useful to include the assignment operator (as it will be generated anyway)
Martin York
@Martin: yes, it was just a quickly written down example. IIRC I added the copy constructor simply to visually match the destructors.
Francesco
A: 

As Daniel mentions, RAM used by an application is not necessarily an indicator of a memory leak. With respect to the behavior you notice regarding vectors, a vector guarantees that the memory layout is contiguous & hence when you create a vector of size 99999999, all the 99999999 elements are laid out in sequence & would constitute a pretty sizable chunk of memory. Deleting this would definitely impact process size. A map behaves differently (as per Wikipedia, its often implemented as a self balancing binary tree) so I guess deleting it causes fragmentation in the process memory space & maybe due to that the process memory does not drop immediately. The best way to detect memory leaks would be to use a tool like valgrind which will clearly indicate whats wrong.

Raam
Though wikipedia is a good starting point for research it is not a good place to quote as a reference (Mr. Wales has been quoted several times on this subject). It is a good place for leading you to authoritative resources though ( in this case the requirements of the c++ STL containers) which should show you that there is no requirement to implement a map as a balanced tree) (though you are correct that most implementations do use this method.
Martin York
@Martin - Agreed, thanks for pointing it out. Will definitely keep this in mind.
Raam