I found a situation where vectors behave like leaking memory and could boil it down to a minimal working example. In this example I make (in a function) a vector which holds three vectors of char. Firstly, these vectors of char get pushed a large number of elements and their capacities are shrinked to their sizes. Then one-element sized vectors are assigned over the large vectors. The problem is now, that the used memory is too large and even when the function returns and the vectors are destroyed, the memory is not freed up. How do I get the memory back? Why does it show this bahaviour? What can I do to avoid this leaking behaviour?
Here the example code (sorry for the length):
#include <iostream>
#include <vector>
#include <string>
#include <fstream>
using namespace std;
// see http://man7.org/linux/man-pages/man5/proc.5.html at /proc/[pid]/status
string meminfo() {
// memory information is in lines 11 - 20 of /proc/self/status
ifstream stat_stream("/proc/self/status",ios_base::in);
// get VmSize from line 12
string s;
for ( int linenum = 0; linenum < 12; ++linenum )
getline(stat_stream,s);
stat_stream.close();
return s;
}
void f() {
vector<vector<char>> mem(3); // with 1,2 memory is fine
size_t size = 16777215; // with 16777216 or greater memory is fine
for ( vector<char>& v : mem ) {
for ( unsigned int i = 0; i < size; ++i )
v.push_back(i);
v.shrink_to_fit(); // without this call memory is fine
}
cout << "Allocated vectors with capacities ";
for ( vector<char>& v : mem )
cout << v.capacity() << ", ";
cout << endl << "used memory is now: " << meminfo() << endl;
for ( vector<char>& v : mem ) {
v = vector<char>{1};
if ( v.size() != v.capacity() )
cout << "Capacity larger than size." << endl;
}
cout << "Shrinked vectors down to capacity 1." << endl
<< "Used memory is now: " << meminfo() << endl;
}
int main() {
cout << "At beginning of main: " << meminfo() << endl;
f();
cout << "At end of main: " << meminfo() << endl;
return 0;
}
And the output on my machine:
At beginning of main: VmSize: 12516 kB
Allocated vectors with capacities 16777215, 16777215, 16777215,
used memory is now: VmSize: 78060 kB
Shrinked vectors down to capacity 1.
Used memory is now: VmSize: 61672 kB
At end of main: VmSize: 61672 kB
However, valgrind does not see a memory leak.
I guess the parameters in the example are system dependent to show the strange bahaviour. I use Linux Mint Debian Edition with a g++ 4.8.2 and a x86_64 kernel. I compile with:
g++ -std=c++11 -O0 -Wall memory.cpp -o memory
and tried also -O3 and no explicit setting for optimization.
Some interesting points are:
v = vector<char>{1};
by v.clear(); v.shrink_to_fit(); v.push_back(1);
the problem stays the same. Replacing the pushing and shrinking for the large vectors by v = vector<char>(16777215);
'solves' the memory problem.In the real world application I use vectors to collect operations that should be applied to a stiffness matrix of an FEM simulation. Since I want to get to the limits of what is possible with the available memory (also in terms of speed), I need to save the unfreed memory to avoid swapping. Since swapping really happens, I assume the VmSize value is reliable.
std::vector does not cause memory leaks, careless programmers do. You should also include an example that actually exhibits the behavior you are experiencing, including calls to the CRT debug API. There's a good possibility that you're incorrectly interpreting the leaks based on when they are reported.
Memory leakage occurs in C++ when programmers allocates memory by using new keyword and forgets to deallocate the memory by using delete() function or delete[] operator. One of the most memory leakage occurs in C++ by using wrong delete operator.
As mentioned above, std::vector is a templated class that represents dynamic arrays. std::vector typically allocates memory on the heap (unless you override this behavior with your own allocator). The std::vector class abstracts memory management, as it grows and shrinks automatically if elements are added or removed.
1) std::vector is a sequence container that encapsulates dynamic size arrays. 2) std::pmr::vector is an alias template that uses a polymorphic allocator. The elements are stored contiguously, which means that elements can be accessed not only through iterators, but also using offsets to regular pointers to elements.
The problem is that you're misunderstand the meaning of 'freeing' memory in a C++ context. When your application frees memory (using shrink_to_fit
or deleting objects or whatever), its actually just releasing the memory to the C++ runtime and NOT NECESSARILY releasing it back to the system for other processes to use. The C++ runtime may choose to retain the memory for reuse later in the same process.
Generally, this happens when the memory is fragmented -- the free memory is surrounded (in the VM space of the program) by in-use memory. Only when the freed memory is at the end of the program's memory space will the C++ runtime choose to (or be able to) return it to the system.
Generally this memory retention is not a problem, as it can usually be reused when more memory is requested by the application. The problem you may have is that, because the C++ runtime cannot move around in-use block of memory, you may not be able to reuse free chunks that are too small. There are all kinds of tricks and heuristics that the runtime may use to try to avoid the situation, but they don't always work.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With