STL and pooling memory

A

aaaaa

Hi all,
Does anybody know if STLPort or SGI STL standard allocators do memory
pooling for the list, map and set?


Also I have had a look at the BOOST pool_alloc (to be used as a pooling
allocator for lists), but looking into the code it doesn't seem to ever
release (to the global ::free) the memory that was once allocated.

I can understand that such memory can be re-used if I have another list
of the same object types later in the program, but it seems to me that
such pool_alloc should anyway release blocks which happen to be
completely free (*) otherwise the program will always appear to have the
peak memory allocation to the operating system. Like leaking! Doesn't it
really ever free the blocks, or it's my overlook?


(*) there are likely to be many totally free blocks after you finish
working with a bunch of pooled lists, if the implementation is what it
seemed to me: every new alloc call always returns the first free slot:
it's an autodefragmenting algorithm
 
K

Kai-Uwe Bux

aaaaa said:
Hi all,
Does anybody know if STLPort or SGI STL standard allocators do memory
pooling for the list, map and set?

I recall that SGI had a web page where they explained that they do some
pooling in their allocators. I do not know about STLPort.
Also I have had a look at the BOOST pool_alloc (to be used as a pooling
allocator for lists), but looking into the code it doesn't seem to ever
release (to the global ::free) the memory that was once allocated.

I can understand that such memory can be re-used if I have another list
of the same object types later in the program, but it seems to me that
such pool_alloc should anyway release blocks which happen to be
completely free (*) otherwise the program will always appear to have the
peak memory allocation to the operating system. Like leaking! Doesn't it
really ever free the blocks, or it's my overlook?

Are you sure that a call to free() will release the memory to your
operating system. As far as I understand the language of the standard, the
only guarantee given for free() is that a deallocated region will be
available to malloc() calls from the same program. (Actually, the C
standard, from which C++ inherits free(), can be read so that the
postcondition of free() actually is that the memory will be available for
subsequent calls to malloc() in which case the memory must not be returned
to the operating system.)

On my system I just used the following code to check the behavior of free.
I conforms the the interpretation of the standard that I outlined: at no
point, memory is returned to the operating system.


#include <list>
#include <iostream>
#include <string>

typedef char page [1024];
typedef page* page_ptr;

int main ( void ) {
std::list< page_ptr > ptr_list;
std::cout << "allocating 300 MB of memory.\n";
for ( unsigned int i = 0; i < 300000; ++i ) {
ptr_list.push_back( reinterpret_cast< page_ptr >( malloc( sizeof( page
) ) ) );
}

{
std:: cout << "allocation done, hit enter for deallocation.";
std::string line;
std::getline( std::cin, line );
std::cout << "\n";
}

while( ! ptr_list.empty() ) {
free( ptr_list.back() );
ptr_list.pop_back();
}

{
std:: cout << "deallocation done, hit.";
std::string line;
std::getline( std::cin, line );
std::cout << "\n";
}

std::cout << "allocating 300 MB of memory again.\n";
for ( unsigned int i = 0; i < 300000; ++i ) {
ptr_list.push_back( reinterpret_cast< page_ptr >( malloc( sizeof( page
) ) ) );
}

{
std:: cout << "allocation done, hit enter for deallocation.";
std::string line;
std::getline( std::cin, line );
std::cout << "\n";
}

while( ! ptr_list.empty() ) {
free( ptr_list.back() );
ptr_list.pop_back();
}

{
std:: cout << "hit enter to quit.";
std::string line;
std::getline( std::cin, line );
std::cout << "\n";
}

}


If you really need to return memory to the operating system, you will have
to write your own allocator and use system calls, which are system specific
and considered off topic in this group.


Best

Kai-Uwe Bux
 
P

Pete Becker

aaaaa said:
I can understand that such memory can be re-used if I have another list
of the same object types later in the program, but it seems to me that
such pool_alloc should anyway release blocks which happen to be
completely free (*) otherwise the program will always appear to have the
peak memory allocation to the operating system. Like leaking! Doesn't it
really ever free the blocks, or it's my overlook?

You might want to look at our CoreX package, which has a toolkit for
building custom allocators. You can write allocators that sequester
their memory, so that it's not available to the rest of the application,
and you can write allocators that release their memory.
 
T

Tom Widmer

Hi all,
Does anybody know if STLPort or SGI STL standard allocators do memory
pooling for the list, map and set?

Yes, they do, and it's configurable with #defines (but on by default
IIRC). Read the docs.
Also I have had a look at the BOOST pool_alloc (to be used as a pooling
allocator for lists), but looking into the code it doesn't seem to ever
release (to the global ::free) the memory that was once allocated.

That sounds correct. Note that you should be using fast_pool_allocator
for std::list, since I think it's faster for unit allocations such as
used by list.

You can manually free slack space by using the underlying singleton
pool allocator. Something like:

singleton_pool<fast_pool_allocator_tag,
size_of_list_node>::release_memory();

This hitch is working out the size of a list node portably, and I'm
not sure there's a way of doing it. You could guess like this:

template <class T>
struct list_node_sizer
{
test* pre;
test* post;
T t;
};

singleton_pool<fast_pool_allocator_tag,
I can understand that such memory can be re-used if I have another list
of the same object types later in the program, but it seems to me that
such pool_alloc should anyway release blocks which happen to be
completely free (*) otherwise the program will always appear to have the
peak memory allocation to the operating system. Like leaking! Doesn't it
really ever free the blocks, or it's my overlook?

If you want to control memory usage, it might be better to use a
non-singleton allocator. boost don't have one, but I'm sure one can be
written based on what they've got - the hardest thing is handling
rebound copies of the allocator.

Tom
 
A

aaaaa

Kai-Uwe Bux said:
aaaaa wrote:

Are you sure that a call to free() will release the memory to your
operating system.
On my system I just used the following code...

DOH!?!?
REALLY!?!?

Excuse me, you are telling me that to the OS a C++ program will always
appear as occupying as much memory as its peak usage?

Anybody else can please confirm?!


All the applications I remember of, under Windows (my OS) do appear to
decrease the memory usage sometimes, and I'm pretty sure that most of
them are written in C or C++.
 
P

Pete Becker

aaaaa said:
Excuse me, you are telling me that to the OS a C++ program will always
appear as occupying as much memory as its peak usage?

Not always, but often.
 
K

Kai-Uwe Bux

aaaaa said:
DOH!?!?
REALLY!?!?

Excuse me, you are telling me that to the OS a C++ program will always
appear as occupying as much memory as its peak usage?

No.

What I was saying, in the part you snipped, was that free() does not have
to return memory to the OS. Of course, the OS offers system calls for
programs to obtain and return memory. However, these are system specific,
not known to me, and not covered in the C or C++ standard. You will be
better off to try in news group for your platform.
Anybody else can please confirm?!


All the applications I remember of, under Windows (my OS) do appear to
decrease the memory usage sometimes, and I'm pretty sure that most of
them are written in C or C++.

And I am pretty sure, they use appropriate system calls to achieve that,
unless free() does some non-standard magic in the C/C++ library that ships
with your Windows version. You can modify the code I provided to see for
yourself what happens on your machine. I do not use Windows, and actually,
I would be interested in your results.


Best

Kai-Uwe Bux
 
A

aaaaa

Ok I understand now, thanks.

I tried your code: it does return it to the OS (windows 2000): the
"VM-Size" in the task manager drops to ~0 during deallocation.

However I noticed that it takes an incredible amount of time to
deallocate! Just a few seconds to allocate 300M but something like 5
minutes to deallocate it!!

This was with VC++7 native STL. I might give a try to STLPort in the
future: if it pools the memory it should be faster. However, your
independent mallocs and frees would not be affected anyway of course.

Now really I see why memory pools and the copying garbage collectors are
useful.
 
A

aaaaa

Tom said:
Yes, they do, and it's configurable with #defines (but on by default
IIRC). Read the docs.


Would you point me to such "docs" because I don't appear to be able to
find them

Thanks
 
A

aaaaa

Ok... I thought you had some special doc pages which claim that they do
pool the memory and explain how to use the #defines :)
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,579
Members
45,053
Latest member
BrodieSola

Latest Threads

Top