开发者

Is stack address shared by Heap addresses?

I read On most operating systems, t开发者_开发技巧he addresses in memory starts from highest to lowest. So I am wondering if the heap, stack, and global memory all fall under the same ordering..?

If I created...

pointerType* pointer = new pointerType  //creates memory address 0xffffff

And then created a local varible on the stack

localObject object

would localObjects address be 0xfffffe

Or is heap and stack ordering completely different.


the addresses in memory starts from highest to lowest

Are the addresses of the houses on your street ordered from highest to lowest, or from lowest to highest? Well, that depends on which way you're driving.

Just like postal addresses, memory addresses aren't really ordered at all. Each address simply identifies a unique location in memory (At least conceptually. We'll ignore, for a moment, segmented or virtual memory).

But when your mail carrier delivers the daily mail, he most likely does work in either highest-to-lowest or lowest-to-highest order (probably both, down one side of the street, and up the other side). This is more efficient, of course, than jumping from house to house at random. In addition, it makes the carrier's job much simpler. If he were to jump from house to house in a random order, it would be difficult to keep track of which houses he had already visited, and which ones still needed delivery. If he simply goes in order, then the position of his truck is all he needs to keep track of.

A stack is similar to this. It doesn't occupy arbitrary positions in memory, but instead has a first position, and subsequent positions follow in logical order from there. In this way, a stack pointer (often "SP") is all that is needed to keep track of which stack locations are occupied and which are free.

A heap is necessarily different, though. While a stack inherently has a first-in-last-out ordering, a heap is inherently unordered. Heap memory can be allocated and deallocated at any time. Earlier allocations can outlive later allocations. A heap, therefore, must be able to allocate arbitrary address ranges, and has to keep track of them all.

Because of the different ways in which the stack and heap operate, they should occupy different areas of memory. In your example, a second stack allocation would overwrite memory occupied by your heap allocation. Obviously, this would be a bad thing, and is what is referred to as a stack overflow.

Most modern CPUs have all the features necessary to keep stack memory and heap memory completely separate. This is where memory segments and virtual memory come into play. On some platforms, the stack and the heap may be identified by the same address range, while still occupying different areas of physical memory or even secondary storage. A discussion of how this works it outside the scope of this post.

Most modern operating systems don't actually do this, though. More commonly, a "flat" address space is used, where all addresses, whether stack, heap, code, or whatever, refer to the same address space. This makes it easier for the application developer, by obviating the need to juggle segment identifiers for every address.

In a flat address space, the same scheme of separating stack and heap is used that was used in ancient CPUs that had no memory segmentation or virtualization: the stack grows down from the "top" of memory (higher addresses), and the heap grows up from the bottom of memory (lower addresses). A certain point between the two may be picked to be the limit of both, and when one reaches the point, an error condition occurs—either stack overflow or out of memory.

Of course, this description is a huge simplification, but hopefully it gives a better basic understanding.


The stack and the heap are usually in two very different places in memory.


Typically you'll find that the stack grows downward from some starting address and the heap grows upwards from some completely different starting address.

How the stack and heap (it's referred to as dynamic storage in the C++ standard) works exactly though is implementation defined and not governed by the C++ standard.


It depends. On a typical CPU, you have one address space for everything, so any two variables must have different addresses. Most do, however, support virtual addressing, in which case it's possible for two different virtual addresses to refer to the same physical address.

On a DSP (for one example), however, you often have two or three completely separate address spaces -- for example, your code and data will have entirely separate physical addressing (i.e., one set of memory chips connected to one memory bus for data, and a separate set of chips connected to a separate bus for code). In this case, one physical address could refer to either of two separate parts of memory; without knowing what kind of thing it's intended to refer to, the address may not allow you to distinguish between the two at all.


Under modern operating systems it is more complicated than this, but to help get you started:

On most personal computer class systems (*) the stack and the heap are both part of the same address space, but by convention stacks are generally started from high addresses and grow downward as things are pushed onto them, while the heap is best considered to be any RAM that is not part of the stack, global variable space (.data and .bss) or part of the program code (.text), both of which are also in the same address space.

  • This is sort of a lie because x86 processors support segmentation which confuses things, but this is about how the computers are used, not strictly what they support.

This is generally known as a von Newman architecture -- all data and code living in one general purpose address space.

Another architecture type is called Harvard. In Harvard archetectures code lives in ROM and most data lives in RAM and the RAM and ROM do not share address spaces. This means that a function and a variable could have the same numeric address, but still not be at the same location. Atmel's AVR architecture is a good example of this, except for some of the smaller versions which only have registers with no RAM (which will just confuse the matter) and some of the larger versions which extend the address space from 16 bits to 24 bits and may (not sure on this) blur the boundaries of the address spaces.

The 8051 family of processors is different still, and more relevant to your question. Generally these have a small amount of fast RAM which is the stack area and lives in a different address space from the general purpose RAM, which is where global variables and possibly a heap area would live. They also generally have their code in another separate address space.

what the heap is

The heap is really just a way of treating some memory/address space which is not already in use. The algorithms you use to allocate and deallocate memory from this spare memory is what makes it the heap.

what a stack really is

Stacks are often a little bit different because there is often hardware support for them in the form of instructions for call, return, push, and pop, but these aren't even necessary. Hardware support for a system stack does become necessary when you start dealing with interrupts, because the "an interrupt occurred" action of the processor needs to use the stack to save the processor's state before executing an interrupt service routine.

why this is often a lie on desktop machines

Modern desktop/workstation operating systems on modern hardware is usually able to take advantage of memory management hardware to do all kinds of things to distort an application's view of the address space from what it really is to something that is simpler for the application to deal with and allows multiple applications to share RAM.

If you program with threads then your application may have more than one stack since each thread usually needs it's own stack. The memory that will make up this stack is often allocated in a very similar manner to the way memory is allocated from the heap area, and may even use the heap allocation functions. Sometimes it is done differently so that the stack can grow dynamically, though.


pointerType* pointer = new pointerType //creates memory address 0xffffff

You misinterpret 0xffffff. It is not the address of newly allocated memory - it is the address of pointer variable itself. If you want to check where memory was allocated, you need to check the value that is stored in 0xffffff


Both the pointer itself and the local object object are located on the stack. The object the pointer points to is locate on the heap.

That's why in C it's often said that there is only pass-by-value. When you pass a pointer to a function, it's no different then passing an int: the pointer/int o the receiving end of the function parameter is another "thing" on the stack. However, since value of the pointer (the address to the heap object) is copied to the receiving end, the same heap object can be reached.


You can always, y'know, check. This is one of those things where you could find out just by outputting the value and checking it. This is not guaranteed to be the same behavior on all computers or with all compilers, but you can see what the case is for yours. Just printf("0x%x\n", &variable) to see what the variable's address is. Allocate a few things on the heap, allocate a few things on the stack, then check all their addresses, and you will see where both are and also which way each is extending toward.

I usually keep a test project on hand in every language I use just for the purpose of quickly adding something to it to see for myself how it works. Doing so is perfect for situations like this, and you get your answers even faster than StackOverflow can provide them.


The stack and heap aren't mutually exclusive. Imagine these two hypothetical behind-the-scenes compiler implementations:

void PreMain()
{
    char initialHeap[initialHeapSize]
    HeapPointer heapHead = &initialHeap;
    ...
    int returncode = main(argc, argv);
    ...
}

void PreMain()
{
    void * stack = GetFromOSHeap(stackSize);
    // some assembly intrinsic to replace the stack pointer
    ...
    int returncode = main(argc, argv);
    ...
}

You might not find these in a mainstream compiler, but I'll bet there's an embedded system somewhere that works like this.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜