C++, Free-Store VS Heap

C++, Free-Store vs Heap

See http://www.gotw.ca/gotw/009.htm; it can describe the differences between the heap and the free-store far better than I could:

Free-store:

The free store is one of the two
dynamic memory areas, allocated/freed
by new/delete. Object lifetime can be
less than the time the storage is
allocated; that is, free store objects
can have memory allocated without
being immediately initialized, and can
be destroyed without the memory being
immediately deallocated. During the
period when the storage is allocated
but outside the object's lifetime, the
storage may be accessed and
manipulated through a void* but none
of the proto-object's nonstatic
members or member functions may be
accessed, have their addresses taken,
or be otherwise manipulated.

Heap:

The heap is the other dynamic memory
area, allocated/freed by malloc/free
and their variants. Note that while
the default global new and delete
might be implemented in terms of
malloc and free by a particular
compiler, the heap is not the same as
free store and memory allocated in one
area cannot be safely deallocated in
the other. Memory allocated from the
heap can be used for objects of class
type by placement-new construction and
explicit destruction. If so used, the
notes about free store object lifetime
apply similarly here.

What is the difference between the heap and the free store?

Well, the current C++ standard only uses the term "free store" - the only use of "heap" in the Standard is to describe the heap data structure in the Standard Library. So "heap" is not a very useful term to use when trying to discuss C++ problems accurately, though of course everyone does it.

Why should I prefer using the free store over the heap?

The new and delete keywords in C++ usually are implemented in terms of malloc and free, but they're designed to do different things.

In C++, if you say

new T(/* args */)

C++ will do the following:

  • Attempt to allocate enough memory to hold an object of type T.
  • On failure, attempt to use the new handler to free space, eventually throwing a std::bad_alloc object if no memory is available.
  • Attempt construct an object of type T in that block of memory.
  • Automatically deallocate the memory if the construction of the object of type T throws an exception.

If you just use malloc, you have to do all of these steps manually, which would be very, very hard. It might look something like this:

T* memory = nullptr;
while (true) {
memory = static_cast<T*>(malloc(sizeof(T)));
if (memory != nullptr) break;

std::get_new_handler()();
}

try {
new (memory) T(/* args */);
} catch (...) {
free(memory);
throw;
}

There are some other nuances here that I've glossed over (like calling operator new instead of malloc, or handling zero-sized requests, etc.), but I hope this helps explain how new and malloc are different.

So why should you use new over malloc? Well, there's a few reasons:

  • It's much safer. With malloc you can forget to check the return type for a null pointer, or you could request the wrong amount of storage space, or you could forget to call the constructor on the object, or you could forget to deallocate memory if the constructor throws an exception, etc.

  • It's more type-safe. malloc returns a void*, which is just a pointer to a block of memory. Using malloc, you have to cast the pointer to the proper type, which introduces the potential for errors later on.

  • It allows customization. Certain types overload operator new to request memory in an unusual way, such as from a pooled allocator or from certain pieces of memory that might be faster, or using a custom allocator that optimizes over the usage pattern. Given this, you can automatically customize all times where memory is allocated dynamically for an object of type T simply by defining operator new and operator delete. If you use malloc, you have to chase down all memory allocation sites throughout the entire program.

That said, there are some advantages to malloc. If you know for certain that you're allocating objects that are trivial objects (like primitives or structs that just hold data), it might be slightly faster to use malloc. malloc also lets you use realloc, which free doesn't. But honestly, you're probably better off just using std::vector or std::array in cases like this, since they're safer, easier to debug, and with good compiler support are likely to be aggressively optimized.

Hope this helps!

new/delete/free store and malloc/free/heap combinations

new/delete keywords are use the free store

malloc/free keywords are use the heap

i see written somewhere that new use malloc. how could it be? they are not use in the memory segment?

The "free store" in C++ is a term that describes the place where objects of dynamic storage duration live. The term "the heap" is a colloquialism for the same thing. new may use malloc and that's fine.

However, it does other stuff too, such as invoking constructors and, potentially, instead of malloc using some other memory management system (such as a memory pool).

Yes, it is undefined to free an object that you allocated with new, primarily because free does not invoke class destructors. Similarly for deleteing something you created with malloc: to do so would be to mix two different allocation/construction idioms and, although you can make it work, it would be spectacularly difficult to do so robustly.

why this memory segment have two names?

Because "the heap" (which is not even a "memory segment") may not be a heap so it's a stupid term. C++ tried to phase it out by introducing the abstraction "free store". Unfortunately, people keep saying "the heap" because of (a) legacy, (b) copy-cat bikeshedding, (c) ignorance of the purpose/meaning/value of abstraction, and (d) poor education/instruction.

Why does my code occasionally show memory on the free store (heap) growing both up and down? (C++)

The main problem with that code is that you are casting int * to int, an operation that may lose precision, and therefore give you incorrect results.

But, aside from that, this statement is a misapprehansion:

My understanding is that memory allocated on the free store (the heap) should grow upwards as I allocate additional free store memory.

There is no guarantee that new will return objects with sequential addresses, even if they're the same size and there have been no previous allocations. A simple allocator may well do that but it is totally free to allocate objects in any manner it wants.


For example, it may allocate in a round robin method from multiple arenas to reduce resource contention. I believe the jemalloc implementation does this (see here), albeit on an per-thread basis.


Or maybe it has three fixed-address 128-byte buffers to hand out for small allocations so that it doesn't have to fiddle about with memory arenas in programs with small and short-lived buffers. That means the first three will be specific addresses outside the arena, while the fourth is "properly" allocated from the arena.

Yes, I know that may seem a contrived situation but I've actually done something similar in an embedded system where, for the vast majority of allocations, there were less than 64 128-byte allocations in flight at any given time.

Using that method means that most allocations were blindingly fast, using a count and bitmap to figure out free space in the fixed buffers, while still being able to handle larger needs (> 128 bytes) and overflows (> 64 allocations).

And deallocations simply detected if you were freeing one of the fixed blocks and marked it free, rather than having to return it to the arena and possibly coalesce it with adjacent free memory sections.

In other words, something like (with suitable locking to prevent contention, of course):

def free(address):
if address is one of the fixed buffers:
set free bit for that buffer to true
return
call realFree(address)

def alloc(size):
if size is greater than 128 or fixed buffer free count is zero:
return realAlloc(size)
find first free fixed buffer
decrement fixed buffer free count
set free bit for that buffer to false
return address of that buffer

The bottom line is that the values returned by new have certain guarantees but ordering is not one of them.

What is the origin of the term heap for the free store?

Knuth rejects the term "heap" used as a synonym for the free memory store.

Several authors began about 1975 to call the pool of available memory a "heap." But in the present series of books, we will use that word only in its more traditional sense related to priority queues. (Fundamental Algorithms, 3rd ed., p. 435)

What is the use of creating objects on the free store?

In your example, there is none, and it isn't good practice to
use dynamic allocation. Dynamic allocation is used when objects
have identity (or cannot be copied for some other reason), and
the lifetime of the object does not correspond to some
pre-determined lifetime, like static or auto. Dynamic
allocation may also be used in a few cases where copying is
expensive, and the profiler shows that the copying is
a bottleneck; in such cases, using dynamic allocation and
copying a pointer may remove the bottleneck. (But this should
never be done until profiling shows it necessary.)

Can The Free Storage Consume More Memory Left Over?

The new is used to allocate the requested amount of memory(if available) to the object/array variable that you requested. In your case, the pointer p will store the address to this allocated block of memory.

There's only a finite amount of memory that's available to you and so your program can only use from that amount of memory. This will vary from system to system but it will be finite. When you request for allocation of more memory than what can be allocated, the program will probably throw some exception like std::bad_alloc to indicate failure to allocate storage which if unhandled will crash your program.

Does the memory allocated for the free store affect the whole
program's available memory?

YES.

The memory allocation in your program will be from heap storage (C++ knows if as free store). To answer your question, Yes, the allocated memory will reduce the amount of free memory available for other variables to use. There isn't an infinite amount of memory available for your program to use. So you might eventually run out of memory space once you have used up all the space available to you. However, you could also free up the memory once its work is done by using delete operator to free up the used memory space and make it available back again for use.

The memory space allocated to you will be implementation based. C++ itself knows nothing about the heap or how memory is allocated to it.

Huge memory allocation: stack vs heap

The size of the stack is usually around one to few megabytes by default on typical desktop systems. Probably less on embedded devices.

If you allocate more memory than fits on the stack, the operating system will typically terminate the program as soon as you attempt to access the memory.

Does it mean it's recommended to story big amount of data in the heap?

It is recommended to use the free store (dynamic allocation) for big amount of data, because big amount of data would overflow the stack.

Application Manager i saw it is not using that amount of memory (just few KBs).

Typically, an operating system allocates a page of memory for a process when that memory is accessed. Since your program didn't crash due to stack overflow, I suspect that you never accessed the memory, and therefore no memory was allocated for the data.



Related Topics



Leave a reply



Submit