Programming Forums

Programming Forums (http://www.programmingforums.org/forumindex.php)
-   C++ (http://www.programmingforums.org/forum15.html)
-   -   Heap vs. Stack memory (http://www.programmingforums.org/showthread.php?t=11672)

Eric the Red Oct 23rd, 2006 6:17 PM

Heap vs. Stack memory
 
A while back, we had this discussion already. Found here

However, recently after reading through "Sam's c++ in 24 hours" by Jesse Liberty. I came up across this line: in a section on "arrays of pointers":
Quote:

The arrays discussed so far store all their members on the stack. Usually stack memory is severely limited, whereas heap memory is far larger. It is possible to declare each object on the heap and then to store only a pointer to the object in the array. This dramatically reduces the amount of stack memory used.
Later on in the paragraph right before the example "storing an array on the heap" it states:
Quote:


As an indication of the greater memory that this makes possible, the array is expanded from 5 to 500...

(Obviously an exaggeration "5 to 500")

I bolded the points that were a contrast to what you guys were saying.
Now saying that "Usually stack memory is severely limited, isn't BS is it?" For, many people have not mentioned that.

I'm completely confused now, you guys are saying one thing... the books telling me another thing. What's really going on and why has this author gotten away with being able to write (on the back of the book cover) "Over 250,000 readers have learned c++ from author Jesse Liberty".


/-------------------------------------------------

As Grumpy stated "is only",
Quote:

The distinction between the two forms, from a pure C++ perspective, is only to do with how lifetime of objects are managed.
Again Grumpy,

Quote:

From a C++ language perspective, the only purpose of new and delete are to manage dynamic memory. Nothing more, nothing less.
Dawei

Quote:

It has nothing, really, to do with memory architecture and what areas of memory are more "readily" available than others. The "stack" is, in reality, a lifo stack. Items are stored and retrieved in the expected way for lifo stacks.
Now, how is it that my book tends to go in a completely different direction of what you guys are saying. Now, I know there may be a good explanation for this. Please, someone clear this up.

DaWei Oct 23rd, 2006 8:16 PM

Quote:

Usually stack memory is severely limited, whereas heap memory is far larger.
Simply because this statement is not unequivocally true. Back in the days when the stack was severely limited, the heap was generally severely limited (or nonexistent), too. Given a system with a certain amount of memory, one can generally alter the amounts of memory dedicated to each of these from certain default values.

Now, in the world of multiple processes, each user (let's say they're all C/C++ programs) gets so much memory for global/static data, so much for code, and so much for stack (presuming the really common implementation that actually uses stack, and frequently the processor's call stack). The heap is an area common to all and belonging to none until memory is borrowed, by one of the processes, using malloc or new or kin. You are expected to return this borrowed memory. Generally speaking, returning the memory with delete or free doesn't actually put the memory back on the common heap. It's free for use by the process that originally borrowed it. It is returned to the heap when the program exits or when the program overtly returns it to the heap.

Once again, you must distinguish between how an implementation chooses to work with the language, and what the language expresses as requirements. It would be stupid for the language to try to specify what kind of keyboard or drive or display you have. It would be stupid for your keyboard or display to specify what language you must use. You must have intermediaries that marry the two. That's called platform dependency.

Many, many machines still use a processor-controlled stack, often the call stack, to manage local variables, argument passing, and so forth. It's just a fairly simple way to accomplish the task. These machines mostly DO have registers in addition. I don't know of a commercially viable one that doesn't, in fact. I have only used one uP that didn't implement a call stack. That was an old one, and a piece of crap. Many of the earlier non-micro processors did not implement such a beast. Call tracing and parameter passing were the job of the programmer.

I have at least one post on the forum that describes call-stack operation. It is generalized but fairly detailed, as usage varies somewhat from processor to processor and language implementation to language implementation. See here.

Incidentally, if you look into your compiler documentation, you can PROBABLY find a way to increase your stack space and heap space.

Today's typical desktop machine (large numbers, but definitely in the minority when it comes to all computers) often have grossly huge amounts of memory. The term 'severely limited', in reference to such machines, should not be used by a knowledgeable, modern author. Of course, I also take the position that "Learn ________ in 24 hours (or days, or weeks)" is a flagrantly stupid and misleading statement. It's the ploy of a used-car salesman or a politician or some other brand of thief, cheat, liar, or crook.

Eric the Red Oct 23rd, 2006 9:37 PM

Thanks for your response.

I did notice that if I were to do this:

:

main()
{
      Cat aRovert[300000];
    //Car aRovert[30000]; this would work.
    system("PAUSE");
    return EXIT_SUCCESS;
}


my program would crash. Whereas, this:

:

main()
{
    Cat *aRover[300000];
   
        for (int i = 0; i < 300000; i++)
        {
            aRover[i] = new Cat;
        }
    system("PAUSE");
    return EXIT_SUCCESS;
}

wouldn't crash my program.


Furthermore, the crash would happend right as I launched the program. As opposed to getting to a specific point then crashing.

In case you want the class, here it is:

:

#include <iostream>

using namespace std;

//int main(int argc, char *argv[])

class Animal
{
      public:
      Animal () {cout << "In Animal Constructor \n";}
      ~Animal () {cout << "In Animal Destructor \n";}
      void setAge(int age){itsAge = age;}
      int getAge(){return itsAge;}
     
      virtual void doSomething() {cout << "doing animal things";}
     
      protected:
      int itsAge;
};

class Cat : public Animal
{
      public:
      Cat() {cout << "Cat constructor \n";}
      ~Cat() {cout << "Cat destructor \n";}
     
      void doSomething () {cout << "Meow \n";}
      void JumpHigh () {cout << "Jumping high";}
     
      protected:
      int itsHealth;
};


Is this not a symptom of having less memory on the stack then on the heap?

DaWei Oct 23rd, 2006 10:05 PM

Cat *aRover[300000];
defines an array of 300,000 pointers; for a typical 32-bit machine, 1.2 megabytes.

Cat aRover [300000];
defines an array of 300,000 Cats; a much larger quantity. Neither of those sizes are to be considered "severely limited". Severely limited is when you have to spend 3 weeks whittling out 7 bytes so you don't have to buy another 2K EEPROM in production quantities. That's at old sizes and old prices, but you get the picture.

If you need housing for 300,000 cats, you should consider spaying/neutering ;) .

As I mentioned, the heap is available for multiple processes. If everyone used their share fairly, or if you added all the stack made available for ALL processes, you'd probably recognize the equality.

Eric the Red Oct 24th, 2006 12:53 PM

Okay, thank you.

Now, considering that the application crashes when I make 300,000 cats, wouldn't that be a problem in real life situations or am I simply leaving something out. For instance, using a database to do this kind of work?

:

main()
{
      Cat aRovert[300000];
    //Car aRovert[30000];  this would work.
    system("PAUSE");
    return EXIT_SUCCESS;
}


Narue Oct 24th, 2006 2:11 PM

>Now, considering that the application crashes when I make 300,000 cats, wouldn't that be a problem in real life situations
Well designed applications avoid that kind of situation by dividing data sets into manageable pieces. Two good examples are streaming and persistence. If you only need one item at a time then you can stream through the items one by one either by generating or retrieving them, processing them, and then reclaiming or reusing the memory for the next item. If you don't have to have RAM-speed access for every item in the entire set all at once, you can persist most of the set to disk and keep a cache of a much smaller set for quick access.

If you do have to have RAM-speed access for every item in a data set all at once and the size breaks your application, you can start looking for another job because you'll get fired with solutions like that. ;)

Eric the Red Oct 24th, 2006 2:59 PM

Quote:

Originally Posted by DaWei (Post 117360)
Cat *aRover[300000];
defines an array of 300,000 pointers; for a typical 32-bit machine, 1.2 megabytes.

Cat aRover [300000];
defines an array of 300,000 Cats; a much larger quantity. Neither of those sizes are to be considered "severely limited". Severely limited is when you have to spend 3 weeks whittling out 7 bytes so you don't have to buy another 2K EEPROM in production quantities. That's at old sizes and old prices, but you get the picture.

If you need housing for 300,000 cats, you should consider spaying/neutering ;) .

As I mentioned, the heap is available for multiple processes. If everyone used their share fairly, or if you added all the stack made available for ALL processes, you'd probably recognize the equality.


Sorry, I meant

:

Cat * aRover = new Cat[300000]; // doesn't crash program

//Cat aRovert[300000]; // does crash program.


The first line doesn't crash the program. While, if don't comment out the second line, it crashes.

lectricpharaoh Oct 24th, 2006 3:39 PM

Quote:

Originally Posted by Eric the Red (Post 117419)
Sorry, I meant

:

Cat * aRover = new Cat[300000]; // doesn't crash program

//Cat aRovert[300000]; // does crash program.

The first line doesn't crash the program. While, if don't comment out the second line, it crashes.

Again, the first declares a bunch of pointers, whereas the second declares a bunch of Cat objects. Try adding this to see the difference:
:

std::cout << "300000 pointers to Cat = " << 300000 * sizeof(Cat*) << " bytes needed\n";
std::cout << "300000 actual Cat objects = " << 300000 * sizeof(Cat) << " bytes needed\n";


Eric the Red Oct 24th, 2006 4:18 PM

Quote:

Originally Posted by lectricpharaoh (Post 117422)
Again, the first declares a bunch of pointers, whereas the second declares a bunch of Cat objects.

You're incorrect, unless this book is wrong again... ROFL.

This:
Quote:



Cat * aRover = new Cat[300000];

Declares a pointer to an array of 300000 Cats. "the address in the pointer aRover is the adress of the first item in that array" (my book)

Whereas, this.. as Dawei said
:

Cat *aRover[300000];

Defines an array of 300,000 pointers to Cats.

Narue Oct 24th, 2006 4:36 PM

>The first line doesn't crash the program. While, if don't comment out the second line, it crashes.
As expected. You can only declare an array of a certain size before it trashes your computer. The second line creates such an array while the first line doesn't create an array at all. It simply allocates a block of dynamic memory and points a pointer to it. If you don't mind me being inaccurate for the sake of simplicity, it goes like this:

Anything you create with new is on the heap, and the heap is virtually (haha! I made a funny) limitless.
Anything else is on the stack, and the stack is very limited by comparison.


All times are GMT -5. The time now is 1:16 AM.

Powered by vBulletin® Version 3.7.0, Copyright ©2000 - 2008, Jelsoft Enterprises Ltd.
Copyright ©2007 DaniWeb® LLC