Memory Allocation/Deallocation?
The Memory Model
The C++ standard has a memory model. It attempts to model the memory in a computer system in a generic way. The standard defines that a byte is a storage unit in the memory model and that memory is made up of bytes (§1.7):
The fundamental storage unit in the C++ memory model is the byte. [...] The memory available to a C++ program consists of one or more sequences of contiguous bytes.
The Object Model
The standard always provides an object model. This specifies that an object is a region of storage (so it is made up of bytes and resides in memory) (§1.8):
The constructs in a C++ program create, destroy, refer to, access, and manipulate objects. An object is a region of storage.
So there we go. Memory is where objects are stored. To store an object in memory, the required region of storage must be allocated.
Allocation and Deallocation Functions
The standard provides two implicitly declared global scope allocation functions:
void* operator new(std::size_t);
void* operator new[](std::size_t);
How these are implemented is not the standard's concern. All that matters is that they should return a pointer to some region of storage with the number of bytes corresponding to the argument passed (§3.7.4.1):
The allocation function attempts to allocate the requested amount of storage. If it is successful, it shall return the address of the start of a block of storage whose length in bytes shall be at least as large as the requested size. There are no constraints on the contents of the allocated storage on return from the allocation function.
It also defines two corresponding deallocation functions:
void operator delete(void*);
void operator delete[](void*);
Which are defined to deallocate storage that has previously been allocated (§3.7.4.2):
If the argument given to a deallocation function in the standard library is a pointer that is not the null pointer value (4.10), the deallocation function shall deallocate the storage referenced by the pointer, rendering invalid all pointers referring to any part of the deallocated storage.
new
and delete
Typically, you should not need to use the allocation and deallocation functions directly because they only give you uninitialised memory. Instead, in C++ you should be using new
and delete
to dynamically allocate objects. A new-expression obtains storage for the requested type by using one of the above allocation functions and then initialises that object in some way. For example new int()
will allocate space for an int
object and then initialise it to 0. See §5.3.4:
A new-expression obtains storage for the object by calling an allocation function (3.7.4.1).
[...]
A new-expression that creates an object of type T initializes that object [...]
In the opposite direction, delete
will call the destructor of an object (if any) and then deallocate the storage (§5.3.5):
If the value of the operand of the delete-expression is not a null pointer value, the delete-expression will invoke the destructor (if any) for the object or the elements of the array being deleted.
[...]
If the value of the operand of the delete-expression is not a null pointer value, the delete-expression will call a deallocation function (3.7.4.2).
Other Allocations
However, these are not the only ways that storage is allocated or deallocated. Many constructs of the language implicitly require allocation of storage. For example, giving an object definition, like int a;
, also requires storage (§7):
A definition causes the appropriate amount of storage to be reserved and any appropriate initialization (8.5) to be done.
C standard library: malloc
and free
In addition, the <cstdlib>
header brings in the contents of the stdlib.h
C standard library, which includes the malloc
and free
functions. They are also defined, by the C standard, to allocate and deallocate memory, much like the allocation and deallocation functions defined by the C++ standard. Here's the definition of malloc
(C99 §7.20.3.3):
void *malloc(size_t size);
Description
Themalloc
function allocates space for an object whose size is specified bysize
and
whose value is indeterminate.
Returns
Themalloc
function returns either a null pointer or a pointer to the allocated space.
And the definition of free
(C99 §7.20.3.2):
void free(void *ptr);
Description
Thefree
function causes the space pointed to byptr
to be deallocated, that is, made
available for further allocation. Ifptr
is a null pointer, no action occurs. Otherwise, if the argument does not match a pointer earlier returned by thecalloc
,malloc
, orrealloc
function, or if the space has been deallocated by a call tofree
orrealloc
,
the behavior is undefined.
However, there's never a good excuse to be using malloc
and free
in C++. As described before, C++ has its own alternatives.
Answers to Questions
So to answer your questions directly:
Where is the "memory" that is being allocated?
The C++ standard doesn't care. It simply says that the program has some memory which is made up of bytes. This memory can be allocated.
What is this "memory"? Space in an array? Or something else?
As far as the standard is concerned, the memory is just a sequence of bytes. This is purposefully very generic, as the standard only tries to model typical computer systems. You can, for the most part, think of it as a model of the RAM of your computer.
What happens exactly when this "memory" gets allocated?
Allocating memory makes some region of storage available for use by the program. Objects are initialized in allocated memory. All you need to know is that you can allocate memory. The actual allocation of physical memory to your process tends to be done by the operating system.
What happens exactly when the memory gets deallocated?
Deallocating some previously allocated memory causes that memory to be unavailable to the program. It becomes deallocated storage.
It would also really help me if someone could answer what malloc does in these C++ lines:
char* x;
x = (char*) malloc (8);Here,
malloc
is simply allocating 8 bytes of memory. The pointer it returns is being cast to achar*
and stored inx
.
Memory allocation/deallocation when working with C# and C++ unmanaged
It's really simple!
- Depends
- Depends
Eh, Sorry about that.
- Under typical conditions, C# will keep track of the memory and get rid of it any time after it's no longer used on the C# side. It has no way of tracking references on the C++ side, so one common mistake in interop is that the memory is deallocated before the unmanaged side is done with it (resulting in loads of FUN). This only applies for cases where the memory is directly referenced, not when its copied (the typical case being a
byte[]
that's pinned for the duration of the unmanaged call). Don't use automatic marshalling when the life-time of the object/pointer being passed to unmanaged code is supposed to be longer than the run of the invoked method. - Under typical conditions, C# has no way of tracking memory allocations in the C++ code, so you can't rely on automatic memory management. There are exceptions (e.g. some COM scenarios), but you'll almost always need to manage the memory manually. This usually means sending the pointer back to the C++ code to do the deallocation, unless it used a global allocator of some kind (e.g. CoMemoryInitialize). Remember that in the unmanaged world, there is no one memory manager that you can safely invoke to dispose of memory; you don't really have the necessary information anyway.
This only applies to pointers, of course. Passing integers is perfectly fine, and using automatic marshalling usually means the marshaller takes care of most of the subtleties (though still only in the simplest case, so be careful). Unmanaged code is unmanaged - you need to understand perfectly how the memory is allocated, and how, when and who is responsible for cleaning up the memory.
Memory Allocation/Deallocation Bottleneck?
It's significant, especially as fragmentation grows and the allocator has to hunt harder across larger heaps for the contiguous regions you request. Most performance-sensitive applications typically write their own fixed-size block allocators (eg, they ask the OS for memory 16MB at a time and then parcel it out in fixed blocks of 4kb, 16kb, etc) to avoid this issue.
In games I've seen calls to malloc()/free() consume as much as 15% of the CPU (in poorly written products), or with carefully written and optimized block allocators, as little as 5%. Given that a game has to have a consistent throughput of sixty hertz, having it stall for 500ms while a garbage collector runs occasionally isn't practical.
Dynamic memory allocation/deallocation in MIPS asembly
However, I do not understand how it is possible to deallocate memory back to the heap.
MARS/SPIM do not allow for returning memory back to the heap, AFAIK. Even if they did allow the negative value sbrk like unix does, that only supports returning the most recently allocated (by sbrk) item — and this is different from client expectations that any heap item can be freed.
So, the only thing you can do is provide an intermediate allocator, that keeps track of free'd space, and prefers freed space (e.g. over increasing the heap space with sbrk) for new allocations when possible.
Second, I am unsure how to save dynamic variables by the user.
This is program responsibility — and by that I mean the test program or user program, not the library that implements malloc and free. I presume there will be some test program. That program will invoke your malloc & free implementations and probably will only pass the test by allocating & freeing lots of memory, but staying within the 4k limit of maximum memory.
To succeed in this task, the code must allocate and deallocate memory upon request. If some of the requests cannot be handled, exception handling must activate to resolve the issue.
I have trouble imagining what this means. Obviously, we can terminate the program when a request for memory is made that cannot be satisfied (i.e. out of memory), but this text suggests that exception handling of some sort can resolve the issue.
Does Ada deallocate memory automatically under some circumstances?
As outlined in Memory Management with Ada 2012, cited here, a local variable is typically allocated on a stack; its memory is automatically released when the variable's scope exits. In contrast, a dynamic a variable is typically allocated on a heap; its memory is allocated using new
, and its memory must be reclaimed, usually:
Explicitly, e.g. using an instance of
Unchecked_Deallocation
.Implicitly, e.g. using a controlled type derived from
Finalization
; as noted here, when the scope of a controlled instance exits, automatic finalization callsFinalize
, which reclaims storage in a manner suitable to the type's design.
The children of Ada.Containers
use controlled types internally to encapsulate access values and manage memory automatically. For reference, compare your compiler's implementation of a particular container to the corresponding functional container cited here.
Ada offers a variety of ways to manage memory, summarized on slide 28 in the author's order of preferability:
- Stack-based.
- Container-based.
- Finalization-based.
- Subpool-based.
- Manual allocate/deallocate.
In the particular case of Main
, the program allocates storage for 16 instances of Integer
. As noted on slide 12, "A compiler may reclaim allocated memory when the corresponding access type goes out of scope." For example, a recent version of the GNAT reference manual indicates that the following storage management implementation advice is followed:
A storage pool for an anonymous access type should be created at the point of an allocator for the type, and be reclaimed when the designated object becomes inaccessible.
Absent such an indication, the storage is not required to be reclaimed. It is typically reclaimed by the host operating system when the program exits.
Why deallocating heap memory is much slower than allocating it?
I had much the same idea as @Basile: I wondered whether your base assumption was actually (even close to) correct. Since you tagged the question C++, I wrote a quick benchmark in C++ instead.
#include <vector>
#include <iostream>
#include <numeric>
#include <chrono>
#include <iomanip>
#include <locale>
int main() {
std::cout.imbue(std::locale(""));
using namespace std::chrono;
using factor = microseconds;
auto const size = 2000;
std::vector<int *> allocs(size);
auto start = high_resolution_clock::now();
for (int i = 0; i < size; i++)
allocs[i] = new int[size];
auto stop = high_resolution_clock::now();
auto alloc_time = duration_cast<factor>(stop - start).count();
start = high_resolution_clock::now();
for (int i = 0; i < size; i++)
delete[] allocs[i];
stop = high_resolution_clock::now();
auto del_time = duration_cast<factor>(stop - start).count();
std::cout << std::left << std::setw(20) << "alloc time: " << alloc_time << " uS\n";
std::cout << std::left << std::setw(20) << "del time: " << del_time << " uS\n";
}
I also used VC++ on Windows instead of gcc on Linux. The result wasn't much different though: freeing the memory took substantially less time than allocating it did. Here are the results from three successive runs.
alloc time: 2,381 uS
del time: 1,429 uS
alloc time: 2,764 uS
del time: 1,592 uS
alloc time: 2,492 uS
del time: 1,442 uS
I'd warn, however, allocation and freeing is handled (primarily) by the standard library, so this could be different between one standard library and another (even when using the same compiler). I'd also note that it wouldn't surprise me if this were to change somewhat in multi-threaded code. Although it's not actually correct, there appear to be a few authors who are under the mis-apprehension that freeing in a multithreaded environment requires locking a heap for exclusive access. This can be avoided, but the means to do so isn't necessarily immediately obvious.
Memory allocation and deallocation in separate module
There is no memory leak in the code. It is impossible to make a memory leak with allocatable
entities in Fortran. Only pointer
can cause a memory leak.
With allocatable if something is going out of scope, it is deallocated automatically.
Your main array is a module variable so it is never going out of scope (it is save
implicitly by Fortran 2008 rules). So if you don't deallocate it yourself, it will remain allocated and then deleted by the operating system on the program termination. But that is not normally considered to be a memory leak. It is not really harmful, because there is no way to make some forgotten copies of the array in memory.
The individual components my_size
could go out of scope, when deallocating the large array dS_sn
. In that case they are deallocated automatically by Fortran rules. You don't have to deallocate them one by one.
So you do not really have to do
Do k = 1 , Br_nn_mre
Deallocate(dS_sn(k)%my_size)
End do
Doing just
Deallocate(dS_sn)
is perfectly correct.
Related Topics
Why Is There No Piecewise Tuple Construction
Confused by Squaring MACro Sqr in C
Move Element from Boost Multi_Index Array
Throwing the Fattest People Off of an Overloaded Airplane
Generate All Sequences of Bits Within Hamming Distance T
How to Compare Two Standard Conversion Sequences Use the Rank of Contained Conversions
How to Remove Duplicate Values from a List in C++
Is There a Proper 'Ownership-In-A-Package' for 'Handles' Available
Different Precision in C++ and Fortran
Compiling Code Containing Dynamic Parallelism Fails
What Are These Seemingly-Useless Callq Instructions in My X86 Object Files For
Is It Legal to Write to Std::String
What Is the Size of Sizeof(Vector)? C++
Protected Data in Parent Class Not Available in Child Class