today at work i was testing our application for memory leaks and other memory-related issues and came across interesting side effect of memory handing mechanism in linux. though it's correct, it looks at least surprising when you haven't seen that before. it appears that kernel nowadays perform lazy memory deallocation. consider following code:
#include <vector> #include <iostream> #include <boost/shared_array.hpp> #include <cstring> using namespace std; using namespace boost; int main(void) { vector< shared_array<char> > v; while(true) { // (1) cout<<"size: "; size_t size; cin>>size; cout<<"(re)allocating to "<<size<<"MB"<<endl; size*=1024; // (2) for(size_t i=v.size(); i<size; ++i) { shared_array<char> tmp(new char[1024]); memset( tmp.get(), 0xF0, 1024 ); v.push_back(tmp); } // (3) random_shuffle( v.begin(), v.end() ); // (4) if( size<v.size() ) v.resize(size); // (5) if( size==0 ) { cout<<"deallocating"<<endl; vector< shared_array<char> > tmp; v.swap(tmp); } // (6) cout<<"size is "<<v.size()/1024<<"MB"<<endl<<endl; } return 0; }
this is a sample program that loops forever allocating given amount of memory (in MB), in 1kB chunks. user gives amount of memory to allocate interactively. it goes like this:
now compile and run this application on one terminal and open (h)top on the second, so that you'll be able to see them both. assuming you have 1GB of memory, ~200MB taken by the system (say: 800MB is free), try following sequence of allocations, taking look at (h)top after each step:
in the first run memory usage increases - good, we expected that. in second the same happens – so far, so good. the surprise is 3rd step, when memory usage usually does NOT drop! when you set it back to 500MB size it's still on the same level. now decreasing it to 0 (all memory is freed in program - remember our 'if')… usually does not free memory still. after some time, and some more (de)allocations memory will stabilize at the “real” level. confusing, huh? wait – there's more. now open one more terminal and run out application on it too. try sequence of allocating 500MB and then going back to 0MB on first terminal ((h)top still shows huge memory usage) and now do the same thing on the second terminal. since previous instance freed memory it should be available, right? in my case - on my machines kernel killed application because memory run out!
this is visible side effect of memory handling mechanism. funny, though quite surprising at first. keep in mind that what (h)top shows is now how much memory application uses at that very moment, but instead how much memory system has currently assigned to it.