I think I don't understand dynamic memory

Started by
14 comments, last by Pink Horror 9 years, 1 month ago

yes, but I don't understand exactly what's Dynamic about the _student = new Student("whatever arguments they used"); part

You're using runtime logic to allocate space for a Student. ie. at runtime you're controlling the allocation and deallocation of the Student objects and the memory associated with them. You can create and delete as many or as few as you want.

If you need control of the number of them you create, or when they are created and destroyed, then you need to use "dynamic memory".

Another time you need dynamic memory is if you want to create an object and have its lifetime exist outside of the function it was created in. A function can return a pointer to a dynamically allocated object (which is very different than just returning a copy of the object).

Advertisement
I don't know if this constitutes a "theory", but maybe a good way to answer your qusetion is to illustrate some common scenarios, with examples, where a programmer might reach for dynamic memory allocation.

The programmer cannot predict the number of objects to run computations at compile time. Knowing the exact number of objects in advance is rare, in fact. There are two primary exceptions:
  • The domain itself has hard limits in place. For example, Chess is played on an 8 x 8 board with 16 pieces per player, so a program for playing chess can avoid dynamic allocation for storing the state of the board. However, the number of moves during the game is not known in advance, so dynamic memory would be required to provide a full game log.
  • The designer chooses an arbitrary limitation on some aspect of the program. This can be for a number of reasons, including not wanting to design a flexible UI that can cope with arbitrary amounts of data (thus avoiding complex workflows like search, sort and paging) or to achieve soft real time performance goals( in a game context this could be trying to ensure that no frame takes more than 16.6 milliseconds).
Another reason is that the lifetime of an object is unknown at compile time. It will almost certainly outlast the function that creates it, it may even outlast the object or objects it is first stored in. An example might be a particular map texture in a multi-player FPS client. Provided the server's map rotation continues to require that texture, it would be preferable to avoid unloading and reloading it. However, once the texture is no longer required, it can be remove to make way for the new textures the next map needs instead. Thus any given texture might be stored for the duration of one map, or several.

Another is the behaviour of the object cannot be precisely determined at compile time. Most object oriented languages implement polymorphism by allocating a dynamic amount of memory, and returning some kind of reference to this memory. Other parts of the code might take a more generic reference, e.g. a pointer to a super class in C++, and without knowing the exact size or layout of the object it can be made use of. Some simple games can be implemented such that every game object inherits from a very simple base class with a virtual function for updating itself (e.g. Asteroids). Most people find that this approach typically doesn't scale well once the number of object types starts to grow.

Finally, a programmer may be forced to use dynamic memory because the language or library they are using make use of it. In particular, it is common in C APIs not to expose the definition of a data structure, which provides maximum freedom for the library implementor when making changes. For example, the Simple Directmedia Library (SDL) is a C API which does this. Some of the API calls wouldn't necessarily require dynamic amounts of memory, but by hiding the details the library implementation can change the size of it's data structures without changing the public API. It also makes the API consistent, as now there is a common pattern for interacting with all parts of the API.

Maybe I can try using analogy to explain it.

automatic allocation:

Imagine there is a restaurant with many tables and seats. You and your family go in the restaurant. The mute receptionist sees that you have 5 people, and leads you to a table G, with 5 seats. Now table G is occupied by your family. When you are done eating, you leave the restaurant. The receptionist sees that and table G is unoccupied. The next family of 5 that comes are able to use table G. This whole time, you did not speak to the receptionist at all, because he is mute.

dynamic allocation:

Now Imagine there is another restaurant with many tables and seats. You and your family go in the restaurant. The blind receptionist asks "how many people"? and you tell him 5. The blind receptionist finds an unoccupied table E with enough seats for 5 people. He's blind so he doesn't want to talk and trip, so he tells you where the table is. Now table E is occupied by your family. When you are done eating, you leave the restaurant. However, you forgot to tell the blind receptionist that you left. He still thinks table E is occupied by you, so table E will not be given to any customers.

tables and seats = memory, since they are space.

customers = data, since they are the contents that occupy space.

the act of entering/leaving restaurant = entering and leaving a scope.

the act of being led to a table by the mute receptionist = automatic allocation.

the act of telling the blind receptionist how many seats you need at the minimum, and getting the location of the seats/tables = dynamic allocation.

This analogy omits some details, but I hope that helps.

yes, but I don't understand exactly what's Dynamic about the _student = new Student("whatever arguments they used"); part

The value stored in the pointer returned by Windows (or the Linux kernel)
That number is the address of the RAM cell where the block you just allocated starts.

From the abstract side, the need for variable numbers of objects, variable array sizes, flexible object lifetimes and other uses of dynamic memory should be clear, but there are significant technical differences between different kinds of memory allocation (static, stack, heap).

Operators new and delete, called either directly or behind closed doors in smart pointer classes, interact with the operating system by requesting and releasing memory, which becomes part of the C++ heap; it's the only way to avoid arbitrary process memory limits (particularly stack size), avoid wasting memory by conservatively allocating more static data than needed, and thus have the program run out of memory only if the operating system fails to provide the minimum actually needed amount.

Omae Wa Mou Shindeiru


Dynamic memory means that the memory lifetime isn't managed automatically by the language - like how when you call a function, memory is automatically provided for the various local variables you need.

I think one reason the OP is confused is that this is a confusing explanation. I'd consider things like std::vector to be part of the C++ language (it is part of the standard, even though it is implemented within the language) and it certainly feels more like automatically managed memory than not. In memory-managed languages, such as Java, there is still dynamic memory. Anyway, your second post is much clearer.

In the example provided, the Student object is somewhat of a red-herring. It is using a shared_ptr, which is a tool for handling dynamic memory, but that was an arbitrary choice. It's hard to understand what that shared_ptr is doing there and what it might provide in functionality. It is also being initialized with hard-coded strings, so everything is theoretically known at run-time. A compiler that is super aggressive and awesome at optimizing could replace the program with something that just outputs the correct line.

However, if you imagine a simple change to fill the Student object with information from the console, I think it's more clear what dynamic memory does. The strings within can be of arbitrary size. The memory for them is dynamic regardless of the Student object itself, and they are all automatically freed when the Student goes out of scope. The only limits on those strings are the pointer size, the OS, memory available, etc. - nothing hard-coded into the class. Internally, there must be three arrays for the strings that are allocated dynamically.

On top of that, if you know something about how those objects from the library work, you know there's an array of bytes storing the Student and the reference counter for the shared_ptr, there is a buffer within the ostringstream for building the string, and cin and cout almost certainly use some dynamic memory for handling input and output.

One last note:


The value stored in the pointer returned by Windows (or the Linux kernel)
That number is the address of the RAM cell where the block you just allocated starts.

You're not always getting memory straight from the OS with every "new" call you make. The implementation of the C++ memory manager handles allocating memory within your program, though it may have to allocate memory from the OS if it needs more, and there could be other system calls for making things thread safe, but individual allocations are, in general, the responsibility of the application. How or when it needs a system call to help is up to the memory manager.

This topic is closed to new replies.

Advertisement