6

Sources usually mention that dynamically created variables are allocated on the heap, while functions' variables on the stack. Also the ones on the stack cease to exist automatically when e.g. the function which contains the variable exits. If I understand correctly, data fields of class are on the heap. I do not understand, what is meant by 'dynamic'? As I see it, when the code is running, anything being created is created dynamically on the fly, be it function variables or objects with variables inside them. I would be glad for simple explanation. Thanks

John V
  • 4,898
  • 10
  • 47
  • 73
  • 4
    Are you talking about C++ (or similar) or Java (or other managed language)? Your sentence "data fields of class are on the heap" is inaccurate in C++, but (I believe) correct in Java. – Mat Jan 10 '13 at 16:10
  • You really do need to specify a language. Many languages don't even have a stack/heap, and of those that do, there is a significant degree of difference in how they are handled. – Servy Jan 10 '13 at 17:14
  • What languages do not use stack/heap? I thought it is more like overall concept of memory organization. – John V Jan 10 '13 at 21:16
  • Nearly all lanugages use both, but how they use them is different and improtant. In C++, an object can be on the stack or the heap, depending how it is declared. In java, an object is always on the heap. – mattnz Jan 10 '13 at 22:10
  • 1
    @user970696 A language such as Veralog has no concept of a stack/heap at all. XSLT (if you consider it a language) has no stack/heap. C#, as a language, has no concept of a stack/heap (although the only two existing implementations of that language do use a stack/heap as implementation details, but there's no conceptual reason why another language implementation couldn't avoid a stack entirely). Then of course there are assembler languages which don't have a stack/heap built into the language itself. – Servy Jan 10 '13 at 22:13
  • I have yet to see a useful assembly program that does not implement and use a stack. I think the distinction needs to be made between real world vs theoretical Comp Sci. (e.g.C# has no concept of stack, but every implementation of it uses one - wonder why) – mattnz Jan 11 '13 at 00:25

4 Answers4

4

I agree that "dynamic" is a poor choice of words, but we're stuck with it now. It basically means the memory allocation is done explicitly by the programmer, using something like new or malloc, instead of automatically by the programming language, as in a function's local variables.

Karl Bielefeldt
  • 146,727
  • 38
  • 279
  • 479
  • 1
    Or reserved by the linker, like anything declared `static` or external to a function in C, or FORTRAN `COMMON` blocks (if we're allowed to go back that far). – TMN Jan 10 '13 at 16:32
2

In most contexts, "dynamic" refers to memory that the programmer explicitly allocates, as opposed to the memory that is allocated as the normal part of entering a function (reserving space for parameters, local variables, etc.).

Let's take the following C function as an example:

void foo(int x, int y)
{
  int z;
  char *str = NULL;
  ...
  str = malloc(sizeof *str * y);
  ...
  free(str);
}

When we enter the function, space is automatically reserved on the stack for x, y, z, and the str pointer (remember stack elements are allocated in last-in, first-out order). Moreover, the amount of space to reserve for each object is fixed at compile time (based on the sizes of the respective types). If you look at the stack frame, it will look something like this (assume int and char * are all the same size):

+--------+
|        | <-- y           STACK BOTTOM
+--------+
|        | <-- x
+--------+
|        | <-- z
+--------+
|        | <--str          STACK TOP
+--------+

When we exit the function, all the elements between "STACK BOTTOM" and "STACK TOP" will be popped (deallocated).

I do not control memory allocation at this level; this is all done automatically for me when I enter and leave the function. However, within the function I want to allocate some memory for str to point to. Moreover, the amount of memory I want to allocate isn't fixed, but is determined at runtime from the value of the y parameter. The malloc call reserves some memory from the heap (an area of memory distinct from the stack, which is managed differently as well) and assigns the address of that memory to str. That memory stays allocated until I explicitly release it with a call to free; if I don't do so before the function exits, the str variable gets deallocated (meaning I lose my reference to that dynamically-allocated block), but the memory it points to does not (this is known as a memory leak; once I lose my reference to the dynamic block, I can't free it).

Java behaves ever so slightly differently:

public void foo(int x, int y)
{
  int z;
  String str = new String(); // don't need to specify a length as with malloc
  ...
}

Similar to C, Java will reserve space on the stack for each of x, y, z, and a str pointer (yes, Java uses pointers under the hood, it just doesn't expose pointer operations to the programmer). Similar to C, the new operator reserves memory for the String object on the heap at runtime. Unlike C, Java monitors objects on the heap to see if they are being referenced by anyone (such as the str variable). Once the Java function exits, all references to the dynamic memory cease to exist, and an automatic garbage collector will eventually deallocate that memory, so I don't have to explicitly free it (in fact, Java doesn't provide an equivalent to the free function).

John Bode
  • 10,826
  • 1
  • 31
  • 43
1

You should think of the stack as an optimization, an implementation detail. Unfortunately, the abstraction that is memory management tends to be leaky. Some languages leak it a lot (I'm looking at you C) and some leak it...less (i.e. Java).

When you need memory, by default, you can imagine that it all goes in the heap. It's possible, under any set of circumstances, to use heap memory to solve all problems. Allocations to the heap can be of a size unknown until right when you need it, and can live for an indeterminate amount of time. Allowing those qualities comes at a cost though. Different languages manage it differently, but the point remains that time and effort is spent by the language, in some way, to both allocate, deallocate, and potentially defragment memory in the heap.

Not all memory that's needed needs that level of flexibility. There are a number of very common contexts in computer programming in which the memory needed is of a size known at compile time and with a scope that contains certain well defined properties. When you call a method you know that the information in memory that represents the parameter list, the return value, and the local variables is of a fixed size, and you know that all new allocations of memory will leave scope before any memory stored at the time it was allocated. This follows the exact implementation of the data structure known as a Stack.

A stack, as a general data structure, is where the last in is the first out. You push items onto it, and then pop items off of item. The item poped is the item most recently pushed on (that's still in the structure). So we assume that there's a stack that holds onto memory. When we start execution of a new method we know that the memory we allocate for that method (all methods need memory for their arguments, return value, and local variables). If we push all of that memory onto the stack it will need to be pushed off of the stack before any items "above" it in the stack can be pushed off. This is okay. We know that the memory of the method that called "us" won't need to be freed until after we finish, and we know that any methods we call will have their memory both allocated and freed before we need to be freed.

Managing this type of memory is much easier than managing heap memory. It's very quick and easy to add new memory to the stack, and very easy to take it off. The "stack" is really just a long contiguous block of memory with at pointer to the "end" of the stack. Allocating new memory is as simple as increasing the stack pointer and telling someone which addresses they are allowed to access, and deallocating is as simple as decreasing the stack pointer by a fixed value. Adding/subtracting a fixed value to a pointer is very fast and easy for a computer.

So the entire purpose of the stack is not to allow additional functionality; in fact using the stack is more restrictive than using the heap, and most complex programs tend to have at least some situations in which the restrictions of stack memory are prohibitive, so you'll still need a heap. Stack memory simply allows much quicker allocation and deallocation of a certain uses of memory that meet the restrictions of a stack.

Glorfindel
  • 3,137
  • 6
  • 25
  • 33
Servy
  • 1,966
  • 14
  • 12
  • nitpicking: it's not that C's abstraction leaks a lot; in C, memory management is not abstracted _at all_. You have to manage it yourself. Of course, stack frames are mostly automatic, even if they're explicit.In pre-Ansi C, all local variables had to be declared at the beginning of the function, so the programmer was _very_ conscious of stack memory management. – Javier Jan 10 '13 at 19:57
  • 1
    @Javier It's still abstracted, it's just abstracted a lot less. For example, you aren't just given a big block of memory and manually determining where you want to place your new item, you just call `malloc` and it finds some free space for you. That's abstracting away (some) of the memory management, just a lot less than, say, Java. You are correct though that it's not "leaky" in that it's inadvertent exposure, much of it is intentional, meaning the abstraction didn't mean to hide these types of details to begin with. – Servy Jan 10 '13 at 20:00
  • well, yeah.... but these are not abstractions, they're utility functions. You still get numeric indices into the 'big block of memory' (pointers can be converted back and forth with integers). The use of `malloc()` is just a convention, a way to easily calculate those numeric indices. The biggest abstraction i see is from typed pointers, which count in multiples of some data size instead of individual bytes; OTOH that's not memory management, but memory use. Of course, this is really nitpicking, as said before. – Javier Jan 10 '13 at 20:10
  • 1
    @Javier A "utility function" and an "abstraction" are not mutually exclusive concepts. In fact, virtually all functions are abstractions of some sort. The idea is that you know the public contract; the signature of the function, and don't need to know the specifics of it's implementation, merely how it should be called and what the effects of calling it are. In this specific case, it's an abstraction in that you, as a programmer, don't need to know how to find a block of memory that's free, you can just say you need memory and get some once free memory. – Servy Jan 10 '13 at 20:16
  • -1 : As much of what you have said is incorrect as it is correct. – mattnz Jan 10 '13 at 22:06
  • @mattnz That's a rather meaningless comment. What aspect(s) of the post do you feel are incorrect? – Servy Jan 10 '13 at 22:09
  • The stack is not an optimisation or implementation detail. It is fundimental to how the hardware works. Languages don't leak, the programs written in them do. There is no language agnostic default about where memory comes from, and it cetinly does not "all go on the heap" . I'll stop here, cause I am only into teh second paragraph....... – mattnz Jan 10 '13 at 22:14
  • 1
    @mattnz I refer you to the link in my first sentence. Eric Lippert, who at the time he wrote that, was a Principle developer for the C# compiler, feels that the stack is an implementation detail. It is fundamental to how *some* hardware functions, but not all. Many languages, to varying degrees, try to hide the fact that there is a stack/heap at the hardware and/or OS level (or some aspects of the stack/heap) from programmers using that language. This is an abstraction. Those abstractions do leak, which is why programmers need to know that there is a stack/heap to begin with. – Servy Jan 10 '13 at 22:20
  • 1
    @mattnz "It's possible, under any set of circumstances, to use heap memory to solve all problems." Servy is not saying that any particular language implementation *does* only use a heap, just that they *could*, because a heap is a completely general memory structure. – Caleth Sep 30 '22 at 08:44
0

Dynamic pretty much means the number of bytes is not known until runtime:

 void f(int a) {
    int *array=new int[a];
    ...
 }
 int main() {
   f(10);
   f(22);
 }

Having both f(10) and f(22) supported(without separate instances of f) means that the memory block size changes on the runtime.

tp1
  • 1,902
  • 11
  • 10
  • Sure but if there is a functionc containing values since the beginning? int A=34 – John V Jan 10 '13 at 16:01
  • @user970696: That would be a compiler optimization, it's still a dynamic allocation mechanism. – TMN Jan 10 '13 at 16:29
  • 1
    this is exactly the point. I think the 'dynamic' word was chosen when writing the first C compilers, to separate allocations managed by library functions (`malloc()`/`free()`) from those managed by the compiler (static variables and stack frames) – Javier Jan 10 '13 at 16:37
  • -1 : Some languages can allocate arrays on the stack where the length of the array is unknown till runtime - but that is not normally be considered dynamic. – mattnz Jan 10 '13 at 22:02