Free memory from a long vector
What I wanted to do is to release the memory used by a vector (say vector<vector<int>>) and I used the swap trick, i.e., v.swap(vector<vector<int>>()).
However, what I observed that the swap trick work well for short vectors but NOT for long ones, for example I tried one vector of length 10,000,000, which took 1.3G in memory, after the swap there is still 1.0G not released.
I learned that this has something to do with the C++ runtime library, my question is that there a way to force the memory to be released by the process? I want to make one process release its memory so that another process can use it.
Below is the code I used for testing.
Thanks advance for any help
Code:
#include <iostream>
#include <vector>
using namespace std;
typedef unsigned long long int64;
int main()
{
{
vector<vector<int64>> batch;
{
vector<int64> v;
for (size_t i = 0; i < 12; ++i)
v.push_back(8000000000);
for (size_t i = 0; i < 10000000; ++i)
batch.push_back(v);
}
cout << "pause 1" << endl;
cin.ignore();
{
vector<vector<int64>> tmp;
batch.swap(tmp);
// I tried several things here.
//tmp.swap(batch);
//batch.clear();
//batch.shrink_to_fit();
//batch = tmp;
}
cout << "pause 2" << endl;
cin.ignore();
}
cout << "pause 3" << endl;
cin.ignore();
}
Re: Free memory from a long vector
Quote:
Originally Posted by
larryyueli
What I wanted to do is to release the memory used by a vector (say vector<vector<int>>) and I used the swap trick, i.e., v.swap(vector<vector<int>>()).
However, what I observed that the swap trick work well for short vectors but NOT for long ones, for example I tried one vector of length 10,000,000, which took 1.3G in memory, after the swap there is still 1.0G not released.
1) Operating system?
2) Compiler used?
3) How did you measure the memory usage?
Quote:
I learned that this has something to do with the C++ runtime library, my question is that there a way to force the memory to be released by the process? I want to make one process release its memory so that another process can use it.
The heap is controlled by the compiler's heap manager. It is up to the heap manager to decide whether to release the memory back to the operating system, not vector or any other class you may write that handles dynamically allocated memory.
The "swap trick" just returned the memory to the heap manager. The vector is is no different than any other C++ class you would write yourself that happens to handle dynamically allocated memory. If you wrote a home-made vector class, you would more than likely see the same thing due to the heap manager doing the memory management of the program.
To prove this, debug into the vector code -- you should see "delete" being called when the vector is destroyed, so the issue is not vector -- it's the thing controlling the "new" and "delete" behaviour of your app, and that's the heap manager.
You can always override the default vector allocator if the one that calls the general new/delete doesn't do the job.
Regards,
Paul McKenzie
Re: Free memory from a long vector
Quote:
Originally Posted by
larryyueli
What I wanted to do is to release the memory used by a vector (say vector<vector<int>>) and I used the swap trick, i.e., v.swap(vector<vector<int>>()).
However, what I observed that the swap trick work well for short vectors but NOT for long ones, for example I tried one vector of length 10,000,000, which took 1.3G in memory, after the swap there is still 1.0G not released.
The "swap trick" doesn't release the memory of vector. It reduces excess capacity.
To return all memory allocated by a vector you need to first empy it, then use the "swap trick". Alternatively you can let go of the vector alltogether (for example by calling delete if it's heap allocated or, if it's stack allocated, returning from the function where it's declared).
Re: Free memory from a long vector
Quote:
Originally Posted by nuzzle
The "swap trick" doesn't release the memory of vector. It reduces excess capacity.
Look carefully at larryyueli's first sentence: the vector is swapped with an empty vector.
Quote:
Originally Posted by nuzzle
To return all memory allocated by a vector you need to first empy it, then use the "swap trick". Alternatively you can let go of the vector alltogether (for example by calling delete if it's heap allocated or, if it's stack allocated, returning from the function where it's declared).
As such, these suggestions should not make a difference.
Re: Free memory from a long vector
Note that section 23.2.4.2 of the 2003 standard, and section 23.3.6.3 of the C++0x draft (n3242) state the following:
Quote:
void swap(vector<T,Allocator>& x);
Effects: Exchanges the contents and capacity() of *this with that of x.
Complexity: Constant time.
Therefore, if you swap your batch vector with an empty temporary vector and if your compiler is standard compliant, then when the temporary (after the swap) pops off the stack it should release the memory that your vector once had. What you may find is that your compiler is optimising your code by increasing the scope of the named temporary such that its life-time is greater than you intended.
You could try making the temporary an unnamed temporary as this may (possibly) prevent the compiler from making such an optimisation, since it would be a stronger statement to say that the vector should have a very temporary life-time... i.e. try replacing:
Code:
vector<vector<int64> > tmp; // Note that I have inserted a space between >>
batch.swap(tmp);
with
Code:
vector<vector<int64> >().swap(batch); // Could trying encapsulating this into a separate function call
If that works and you intend to write a C++0X equivalent function (although it will have to be a free function) to shrink_to_fit, then you could write.
Code:
template <typename T, typename Allocator>
void shrink_to_fit(vector<T,Allocator>& x)
{
vector<T, Allocator>(x.begin(), x.end()).swap(x);
}
I hope this all helps... and works.
EDIT:
By the way, can you write back and let us know what happens with this change?
Re: Free memory from a long vector
Playing around with the use of swap() didn't make any difference, I seems the only hope is to use customized allocator, even modified new and delete operator.
Re: Free memory from a long vector
Again, HOW are you determining that the memory isn't being freed? If you're looking at the task manager, then stop. That is not going to tell you the whole story.
As far as releasing memory for another process to use, that's irrelevant. On a 32bit machine, Windows will give every process 4GB, period. 2GB is typically reserved for the OS, and 2 GB is for you to use anyway you want.
Viggy
Re: Free memory from a long vector
Quote:
Originally Posted by
larryyueli
Playing around with the use of swap() didn't make any difference
Please can you answer the three questions that Paul asked - the third of which MrViggy has emphasized. i.e.
1) Operating system?
2) Compiler used?
3) How did you measure the memory usage?
Quote:
Originally Posted by
larryyueli
I seems the only hope is to use customized allocator, even modified new and delete operator.
You can try and write a custom allocator, but I don't believe it will help you. The section Memory, and more specifically its subsection on the default allocator of the 2003 C++ ISO Standard states:
Quote:
void deallocate(pointer p , size_type n );
Requires: p shall be a pointer value obtained from allocate(). n shall equal the value passed as the first argument to the invocation of allocate which returned p .
Effects: Deallocates the storage referenced by p .
Remarks: Uses ::operator delete(void*) (18.4.1), but it is unspecified when this function is called.
It is my understanding that the part that says "but it is unspecified when this function is called", is actually in reference to the call to deallocate() since Allocators are not allowed to hold state.
When the standard library operator delete/delete[] is called, the memory is immediately deallocated. It is not within a compiler vendors best interest to do something other than that, since that is the expected behaviour. The section on Deallocation functions in the 2003 C++ ISO Standard states.
Quote:
If the argument given to a deallocation function in the standard library is a pointer that is not the null pointer value (4.10), the deallocation function shall deallocate the storage referenced by the pointer, rendering invalid all pointers referring to any part of the deallocated storage. The effect of using an invalid pointer value (including passing it to a deallocation function) is undefined.38)
Have you tried printing the capacity of batch after the swap? Is it always small? If not then there must be some unwanted optimisation going on. However, if it is small, then the point that I am trying to make, is that if your compiler is standard compliant, then it is highly unlikely that the deallocation is not taking place, and therefore the problem is either elsewhere, or in the manner that you are recording the memory usage.
Again, answering the three questions that Paul asked might help here.