Returning memory to the OS

J

Jan Bielawski

I have a multi-platform STL question (multi-platform means Windows 32,
64, Linux 64-bit, Mac OS). I'd like for an STL vector to return the
memory to the OS - not just to the heap - upon deallocation, like
exiting the scope. I wrote an allocator with the usual ::eek:perator
delete in its deallocate() function:

void deallocate(pointer p, size_type num) {
::eek:perator delete((void *)p);
}

....but this does not necessarily return the memory to the OS. I found
the function _heapmin() on MSDN web site and it seems to work for
Windows XP 32-bit:

void deallocate(pointer p, size_type num) {
::eek:perator delete((void *)p);
#ifdef WIN32
_heapmin(); // memory goes away stepping past this line
#endif
}

My first question is: is this the way to go about it in general? And
if yes, what are the corresponding system calls for Linux and Mac?

Finally, is there a newsgroup more suited for this type of question?

Thanks!
 
I

Ian Collins

Jan said:
I have a multi-platform STL question (multi-platform means Windows 32,
64, Linux 64-bit, Mac OS). I'd like for an STL vector to return the
memory to the OS - not just to the heap - upon deallocation, like
exiting the scope.

Why? Operating systems are designed to manage their memory, so why
second guess them?
My first question is: is this the way to go about it in general? And
if yes, what are the corresponding system calls for Linux and Mac?
No.

Finally, is there a newsgroup more suited for this type of question?

Platform specific programming groups.
 
R

Richard

[Please do not mail me a copy of your followup]

Jan Bielawski <[email protected]> spake the secret code
I have a multi-platform STL question (multi-platform means Windows 32,
64, Linux 64-bit, Mac OS). I'd like for an STL vector to return the
memory to the OS - not just to the heap - upon deallocation, like
exiting the scope. [...]

Look at the google heap implementation of malloc/free, I believe it
returns memory to the OS.
 
M

Maxim Yegorushkin

I have a multi-platform STL question (multi-platform means Windows 32,
64, Linux 64-bit, Mac OS). I'd like for an STL vector to return the
memory to the OS - not just to the heap - upon deallocation, like
exiting the scope. I wrote an allocator with the usual ::eek:perator
delete in its deallocate() function:

void deallocate(pointer p, size_type num) {
::eek:perator delete((void *)p);
}

...but this does not necessarily return the memory to the OS. I found
the function _heapmin() on MSDN web site and it seems to work for
Windows XP 32-bit:

void deallocate(pointer p, size_type num) {
::eek:perator delete((void *)p);
#ifdef WIN32
_heapmin(); // memory goes away stepping past this line
#endif
}

My first question is: is this the way to go about it in general?

You would need to create another allocator that would do the required
memory management and instantiate std::vector<> with it. Not very
practical for your purpose though because one of the design goals of
std::vector<> is to hide memory management details from the user while
you seem to want to manage memory explicitly.

If you just need a huge array you could allocate it directly from the OS
using POSIX mmap() call or VirtualAlloc() call on Windoze. The
interesting bit here is that operating systems like Linux and Windoze do
demand paging, i.e. mmap() call only reserves a portion of process
virtual address space without actually allocating any memory. Memory is
allocated on demand by pages (most often 4096 bytes on x86)
transparently when you first actually write or read that mmap()ed
memory, thus demand paging. http://en.wikipedia.org/wiki/Demand_paging

On 64-bit platforms this demand paging feature lets you do very
interesting things. Like reserving ridiculously large amounts of memory
and using that as object memory pools. For example, if you application
can theoretically handle maximum of say 1.000.000.000 objects of size 64
bytes, one can reserve 64 * 1.000.000.000 bytes of virtual address
memory space using mmap(). And then allocate objects from the beginning
of that array and deallocate objects back into a free-list. This way you
only use as little memory as possible at the start of the huge array,
eliminating any memory waste as memory is allocated only when you
actually use it.
> And
if yes, what are the corresponding system calls for Linux and Mac?

See http://www.opengroup.org/onlinepubs/000095399/functions/mmap.html
 
J

James Kanze

You would need to create another allocator that would do the
required memory management and instantiate std::vector<> with
it. Not very practical for your purpose though because one of
the design goals of std::vector<> is to hide memory management
details from the user while you seem to want to manage memory
explicitly.

Yes and no. std::vector<> would still take care of the basic
decisions concerning how much to allocate and to free, and when.
A simple memory manager going directly to the OS each time
shouldn't be too difficult (using an anonymous mmap under Unix);
more likely, however, you'd want to be a little bit more
sophisticated, and only go directly to the OS for allocations
larger than some specific size, using the operator new and the
operator delete functions otherwise.
If you just need a huge array you could allocate it directly from the OS
using POSIX mmap() call or VirtualAlloc() call on Windoze. The
interesting bit here is that operating systems like Linux and Windoze do
demand paging, i.e. mmap() call only reserves a portion of process
virtual address space without actually allocating any memory. Memory is
allocated on demand by pages (most often 4096 bytes on x86)
transparently when you first actually write or read that mmap()ed
memory, thus demand paging.http://en.wikipedia.org/wiki/Demand_paging

Except that it's not so transparent as that. It can't be; if
there are no pages left, the system has to do something. And
that something is generally very unpleasant, involving processes
getting killed or hanging. Luckily, this feature can be turned
off under Linux, since you can't write serious software when it
is active.
 
M

Maxim Yegorushkin

Yes and no. std::vector<> would still take care of the basic
decisions concerning how much to allocate and to free, and when.
Agree.

A simple memory manager going directly to the OS each time
shouldn't be too difficult (using an anonymous mmap under Unix);
more likely, however, you'd want to be a little bit more
sophisticated, and only go directly to the OS for allocations
larger than some specific size, using the operator new and the
operator delete functions otherwise.

On Linux default malloc() based on Doug Lea's Malloc does allocate
chunks larger than 128k (tunable) using mmap(). Default GNU libstdc++
new uses malloc(), which does the right thing.
Except that it's not so transparent as that. It can't be; if
there are no pages left, the system has to do something. And
that something is generally very unpleasant, involving processes
getting killed or hanging. Luckily, this feature can be turned
off under Linux, since you can't write serious software when it
is active.

Well, it just swaps out rarely accessed pages of the mapping, as long as
swapping is not explicitly turned off (mlock) for the mapping.

May be I am too spoiled by overpowered servers with large amounts of RAM ;)
 
I

Ian Collins

Maxim said:
Well, it just swaps out rarely accessed pages of the mapping, as long as
swapping is not explicitly turned off (mlock) for the mapping.

Which assumes the system has somewhere to swap to! Try embedded Linux
without swap space sometime...
 
T

Tech07

James Kanze wrote some "stupid" shit and I retorted:

How does it feel to be a dying consultant?
 
J

James Kanze

On 11/10/09 11:49, James Kanze wrote:

[...]
On Linux default malloc() based on Doug Lea's Malloc does
allocate chunks larger than 128k (tunable) using mmap().
Default GNU libstdc++ new uses malloc(), which does the right
thing.

I knew that some malloc's did this, but I didn't know which.
(I've also seen it used for garbage collection---the port of the
Boehm collector I use under Linux uses it, for example.)
Well, it just swaps out rarely accessed pages of the mapping,
as long as swapping is not explicitly turned off (mlock) for
the mapping.

And if there are no pages on the disk? When I said that there
were no pages left, I meant no pages, anywhere. At least on the
Unix machines I've worked on, swap space is a limited resource.
(Admittedly, the limits have gotten rather high in recent
years.) At least in some versions of Linux, the OS starts
killing processes. Not necessarily the ones which are abusing
memory, either---I know of one case where the init process was
killed (so no further logins were possible).
May be I am too spoiled by overpowered servers with large
amounts of RAM ;)

If you don't run out of memory, there's no problem. It's when
you run out of memory and swap space on disk that things get
hairy.
 
M

Maxim Yegorushkin

On 11/10/09 11:49, James Kanze wrote:
[]
Well, it just swaps out rarely accessed pages of the mapping,
as long as swapping is not explicitly turned off (mlock) for
the mapping.

And if there are no pages on the disk? When I said that there
were no pages left, I meant no pages, anywhere. At least on the
Unix machines I've worked on, swap space is a limited resource.
(Admittedly, the limits have gotten rather high in recent
years.) At least in some versions of Linux, the OS starts
killing processes. Not necessarily the ones which are abusing
memory, either---I know of one case where the init process was
killed (so no further logins were possible).

Just to clarify, this out-of-physical-memory situation happens no matter
whether malloc() is used or mmap().

In fact, it is more likely to happen sooner when malloc() is used. This
is because malloc() allocated chunks of memory have a housekeeping
header on the negative offset of the returned pointer, in other words,
there is a memory overhead for each malloc() allocation.

For Linux default malloc(), the header size is 4 bytes in 32-bit mode
and 8 bytes in 64-bit mode. This overhead is necessary since the only
argument to free() is a pointer and it needs to figure out which way it
was allocated (since depending on the size, malloc() allocates memory in
four different ways) in order to deallocate it correctly. Please see
comments in
http://cvs.savannah.gnu.org/viewvc/libc/malloc/malloc.c?revision=1.200&root=libc&view=markup

On the other hand, there is no per-allocation memory overhead when
memory pools of same size objects are used.

Another useful property of mmap()-based memory pools is that when the
object size is a power of two the objects are perfectly aligned with
respect to CPU cache resulting in better cache utilization and less
cache and TLB misses.
 

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

No members online now.

Forum statistics

Threads
473,756
Messages
2,569,534
Members
45,007
Latest member
OrderFitnessKetoCapsules

Latest Threads

Top