Realloc only if the memory address doesn't change [duplicate] - c++

This question already has answers here:
realloc without freeing old memory
(7 answers)
Closed 2 years ago.
Is it possible to reallocate more space only if the address stays the same? Like a type of realloc that fails if it cannot do that and would have to return a new address.
While putting final optimizing touches on my specialized pod container, using realloc does yield a reasonable performance boost in my testing but I cannot invalidate pointers to the data during the lifetime of the container and thus cannot leave this up to chance and good luck.

This is generally not feasible in a dynamic memory allocation scheme. An allocator could guarantee memory at the same address would be available only by reserving as much memory as might ever be required at that address to start with. If it does not reserve that much memory for allocation A, then some subsequent allocation B may be placed at some place after A earlier than that maximum potential reservation, and then A could never be enlarged beyond B, since B would be in the way.
One possible way this might be implemented is in a huge address space where each allocation could be given all the virtual address space it might ever need but have physical memory mapped only for the space that has been currently requested. An implementation-dependent custom allocator could be implemented for that.

Related

Proof that shrink_to_fit or swap guarantees to release vector's memory [duplicate]

This question already has answers here:
C++ delete vector, objects, free memory
(7 answers)
Closed 5 years ago.
Can anyone provide a proof that one of the following approaches provide a guarantee to free the vector's memory in a platform independent manner?
vector<double> vec;
//populating vec here
Cleaning up:
1- shrink to fit approach
vec.clear();
vec.shrink_to_fit();
2- swap approach
vector<double>().swap(vec);
Creating a vector with using new is unlikely to do what I think you'd want to do either.
std::vector implementations usually only "guarantee" that they will allocate enough memory to hold the requested number of elements at minimum. The latter is important because asking the OS or runtime for more memory when you need to grow the vector is an expensive operation that may potentially trigger an element copy as well. For that reason, a lot of the implementations use some heuristics to determine how big the allocation is going to be when the vector has to grow to a certain size. For example, one implementation I'm familiar with doubles the size of the allocation every time new memory is required, giving you a 2^x allocation schema.
With an allocation schema like that, trying to shrink a vector from, say, 90 to 70 elements is pretty much guaranteed to keep the allocated memory size the same to reserve for additional room for growth.
If you need exact memory allocation sizes for whatever reason, you'll pretty much either have to use std::array if you know the sizes at compile time, or manage an array yourself.

Will C++ STL vector reserving too many capacity costs lots of memory? [duplicate]

This question already has answers here:
Is there a downside to a significant overestimation in a reserve()?
(5 answers)
Closed 5 years ago.
In my code, if I call vector::reserve(capacity) and allocate more capacity than what I actually need for the vector to hold the elements, then during the running of my program, will the vector always holds the memory, not releasing resource and costs? If so, isn't that kind of memory waste?
Can I risk trying to lower the reserve capacity to the anticipated size of vector and would that make the program run robust and maybe faster?
Would this lower the possibility of running out of memory?
I ran the code on the mobile phone with high computative load tasks, so still need to consider memory overhead.
will the vector always holds the memory, not releasing resource and
costs kind of memory waste?
The vector will not release/reallocate the memory.
If it had reallocated the memory, then all the iterators, references and pointers referencing the elements stored in that vector will be invalidated without notice.
Can I risky trying to lower the reserve(capacity) to the anticipated
size of vector and make the program run robust and maybe faster?
I'd say that a good practice is to call reserve if you know that the vector size will reach eventually a constant size, or has a minimum size. otherwise, lose the call to reserve. let the vector do its own calculations. you will realize that the vector reallocations are probably not the bottleneck of your program.
You can also call shrink_to_fit to make sure that your vector uses exactly the amount of memory it needs.

How operator new knows that memory is allocated [duplicate]

This question already has answers here:
How do malloc() and free() work?
(13 answers)
Closed 7 years ago.
In C++, how may operator new save information that a piece of memory is allocated? AFAIK, it does not work for constant time and have to search for free memory in heap. Or, maybe, it is not about C++, but about OS?
P.S. I do not know whether it is specified by standard or not, whether it is managed by OS or by C++, but how may it in fact be implemented?
There's no simple, standard answer. Most implementations of operator
new/operator delete ultimately forward to malloc/free, but there are a
lot of different algorithms which can be used for those. The only thing that's
more or less universal is that allocation will typically allocate a little bit
more than requested, and use the extra memory (normally in front of the address
actually returned) to maintain some additional information: either the actual
size allocated or a pointer to the end of the block (or the start of the next
block). Except that some algorithms will keep allocations of the same size
together, and be able to determine the size from the address. There is no
single answer to your question.
new is oftentimes implemented on basis of malloc/free.
How does malloc/free implement it? The answer is: It depends on the implementation. Surprisingly: Malloc oftentimes does not keep track of the allocated blocks at all! The only thing, malloc is doing most of the time, is adding a little bit of information containing the size of the block "before" the allocated block. Meaning, that when you allocate 40 bytes, it will allocate 44 bytes (on 32bit machines) and writes the size in the first 4 bytes. It will return the address of this chunk+4 to you.
Malloc/free keeps track of a freelist. A freelist is a list of freed memory chunks that is not (yet) be given back to the operating system. Malloc searches the freelist, when a new block is needed and when a fitting block is available uses that.
But a more exhausting answer about malloc/free, I have given here:
How do malloc() and free() work?
One additional information:
One implication of the fact, that many allocators don't track allocated blocks: When you return memory by free or delete and pass a pointer in, that was not allocated before, you will corrupt your heap, since the system is not able to check if the pointer is valid. The really ugly thing about it is, that in such a case, your program will not dump immediately, but any time after the error-cause occured ... and thus this error would be really ugly to find. That is one reason, memory handling in C/C++ is so hard!
new maintains a data structure to keep track of individually allocated blocks. There are plenty of ways for doing that. Usually, some kind of linked list is used.
Here a small article to illustrate this.

What is slower about dynamic memory usage? [duplicate]

This question already has answers here:
Which is faster: Stack allocation or Heap allocation
(24 answers)
Closed 9 years ago.
I know that its faster to allocate memory on the stack than on the heap, but why is heap memory allocation slower? Is it because stack allocation is continuous and therefore the issue arises because of cache locality? Is it not the usage of the memory after it has been allocated, it is the time taken to allocate which is slower?
Caching issues aside, the CPU stack is just that, a stack, a LIFO list/queue. You remove things from it in the exactly opposite order from the one you put them there. You do not create holes in it by removing something in the middle of it. This makes its management extremely trivial:
memory[--stackpointer] = value; // push
value = memory[stackpointer++]; // pop
Or you could allocate a large chunk:
stackpointer -= size; // allocate
memset(&memory[stackpointer], 0, size); // use
and free it likewise:
stackpointer += size; // free
Your heap, OTOH, does not have the LIFO property. And for that reason it must keep track of all allocated blocks individually. Which means, it has to have some kind of list of free blocks and a list of allocated blocks and it needs to look for big enough blocks when allocating and look for the specified block when freeing and then likely do some block splitting and coalescing in the process. The simple stack does not need to do any of this.
This alone is a significant algorithmic difference between two ways of allocation and deallocation.
Caching and explicit calls to map physical memory into the virtual address space add up as well, but if you consider them to be equal in both cases, you still have a few instructions vs a few dozen to a few hundred instructions of difference.
"Better" may not a good way to describe it, but it usually is "Faster" to allocate memory on the stack, as opposed to on the heap. You are correct that it is the allocation of the memory which is slower, not the use of that memory afterwards.
The reason that heap allocation tends to be slower is that heap managers need to do additional work: they often try to find a block of existing memory that closely approximates the size you are requesting, and when freeing blocks, they typically check adjoining memory areas to see if they can be merged. Stack allocation is simply adding a value to a pointer, nothing more.

Memory Allocation/Deallocation? [closed]

As it currently stands, this question is not a good fit for our Q&A format. We expect answers to be supported by facts, references, or expertise, but this question will likely solicit debate, arguments, polling, or extended discussion. If you feel that this question can be improved and possibly reopened, visit the help center for guidance.
Closed 9 years ago.
I have been looking at memory allocation lately and I am a bit confused about the basics. I haven't been able to wrap my head around the simple stuff. What does it mean to allocate memory? What happens? I would appreciated answers to any of these questions:
Where is the "memory" that is being allocated?
What is this "memory"? Space in an array? Or something else?
What happens exactly when this "memory" gets allocated?
What happens exactly when the memory gets deallocated?
It would also really help me if someone could answer what malloc does in these C++ lines:
char* x;
x = (char*) malloc (8);
Thank you.
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
The malloc function allocates space for an object whose size is specified by size and
whose value is indeterminate.
Returns
The malloc 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
The free function causes the space pointed to by ptr to be deallocated, that is, made
available for further allocation. If ptr is a null pointer, no action occurs. Otherwise, if the argument does not match a pointer earlier returned by the calloc, malloc, or realloc function, or if the space has been deallocated by a call to free or realloc,
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 a char* and stored in x.
1) Where is the "memory" that is being allocated?
This is completely different based on your operating system, programming environment (gcc vs Visual C++ vs Borland C++ vs anything else), computer, available memory, etc. In general, memory is allocated from what is called the heap, region of memory just waiting around for you to use. It will generally use your available RAM. But there are always exceptions. For the most part, so long as it gives us memory, where it comes from isn't a great concern. There are special types of memory, such as virtual memory, which may or may not actually be in RAM at any given time and may get moved off to your hard drive (or similar storage device) if you run out of real memory. A full explanation would be very long!
2) What is this "memory"? Space in an array? Or something else?
Memory is generally the RAM in your computer. If it is helpful to think of memory as a gigantic "array", it certain operates like one, then think of it as a ton of bytes (8 bit values, much like unsigned char values). It starts at an index of 0 at the bottom of memory. Just like before, though, there are tons of exceptions here and some parts of memory may be mapped to hardware, or may not even exist at all!
3) What happens exactly when this "memory" gets allocated?
At any given time there should be (we really hope!) some of it available for software to allocate. How it gets allocated is highly system dependent. In general, a region of memory is allocated, the allocator marks it as used, and then a pointer is given to you to use that tells the program where in all of your system's memory that memory is located. In your example, the program will find a consecutive block of 8 bytes (char) and return a pointer to where it found that block after it marks it as "in use".
4) What happens exactly when the memory gets deallocated?
The system marks that memory as available for use again. This is incredibly complicated because this will often cause holes in memory. Allocate 8 bytes then 8 more bytes, then deallocate the first 8 bytes and you've got a hole. There are entire books written on handling deallocation, memory allocation, etc. So hopefully the short answer will be sufficient!
5) It would also really help me if someone could answer what malloc does in these C++ lines:
REALLY crudely, and assuming it's in a function (by the way, never do this because it doesn't deallocate your memory and causes a memory leak):
void mysample() {
char *x; // 1
x = (char *) malloc(8); // 2
}
1) This is a pointer reserved in the local stack space. It has not be initialized so it points to whatever that bit of memory had in it.
2) It calls malloc with a parameter of 8. The cast just let's C/C++ know you intend for it to be a (char *) because it returns a (void *) meaning it has no type applied. Then the resulting pointer is stored in your x variable.
In very crude x86 32bit assembly, this will look vaguely like
PROC mysample:
; char *x;
x = DWord Ptr [ebp - 4]
enter 4, 0 ; Enter and preserve 4 bytes for use with
; x = (char *) malloc(8);
push 8 ; We're using 8 for Malloc
call malloc ; Call malloc to do it's thing
sub esp, 4 ; Correct the stack
mov x, eax ; Store the return value, which is in EAX, into x
leave
ret
The actual allocation is vaguely described in point 3. Malloc usually just calls a system function for this that handles all the rest, and like everything else here, it's wildly different from OS to OS, system to system, etc.
1 . Where is the "memory" that is being allocated?
From a language perspective, this isn't specified, and mostly because the fine details often don't matter. Also, the C++ standard tends to err on the side of under-specifying hardware details, to minimise unnecessary restrictions (both on the platforms compilers can run on, and on possible optimisations).
sftrabbit's answer gives a great overview of this end of things (and it's all you really need), but I can give a couple of worked examples in case that helps.
Example 1:
On a sufficiently old single-user computer (or a sufficiently small embedded one), most of the physical RAM may be directly available to your program. In this scenario, calling malloc or new is essentially internal book-keeping, allowing the runtime library to track which chunks of that RAM are currently in use. You can do this manually, but it gets tedious pretty quickly.
Example 2:
On a modern multitasking operating system, the physical RAM is shared with many processes and other tasks including kernel threads. It's also used for disk caching and I/O buffering in the background, and is augmented by the virtual memory subsystem which can swap data to disk (or some other storage device) when they're not being used.
In this scenario, calling new may first check whether your process already has enough space free internally, and request more from the OS if not. Whatever memory is returned may be physical, or it may be virtual (in which case physical RAM may not be assigned to store it until it's actually accessed). You can't even tell the difference, at least without using platform-specific APIs, because the memory hardware and kernel conspire to hide it from you.
2 . What is this "memory"? Space in an array? Or something else?
In example 1, it's something like space in an array: the address returned identifies an addressable chunk of physical RAM. Even here, RAM addresses aren't necessarily flat or contiguous - some addresses may be reserved for ROM, or for I/O ports.
In example 2, it's an index into something more virtual: your process' address space. This is an abstraction used to hide the underlying virtual memory details from your process. When you access this address, the memory hardware may directly access some real RAM, or it might need to ask the virtual memory subsystem to provide some.
3 . What happens exactly when this "memory" gets allocated?
In general, a pointer is returned which you can use to store as many bytes as you asked for. In both cases, malloc or the new operator will do some housekeeping to track which parts of your process' address space are used and which are free.
4 . What happens exactly when the memory gets deallocated?
Again in general, free or delete will do some housekeeping so they know that memory is available to be re-allocated.
It would also really help me if someone could answer what malloc does in these C++ lines:
char* x;
x = (char*) malloc (8);
It returns a pointer which is either NULL (if it couldn't find the 8 bytes you want), or some non-NULL value.
The only things you can usefully say about this non-NULL value are that:
it's legal (and safe) to access each of those 8 bytes x[0]..x[7],
it's illegal (undefined behaviour) to access x[-1] or x[8] or actually any x[i] unless 0 <= i <= 7
it's legal to compare any of x, x+1, ..., x+8 (although you can't dereference the last of those)
if your platform/hardware/whatever have any restrictions on where you can store data in memory, then x meets them
To allocate memory means to ask the operating system for memory. It means that it is the program itself to ask for "space" in RAM when only when it needs it. For example if you want to use an array but you don't know its size before the program runs, you can do two things:
- declare and array[x] with x dediced by you, arbitrary long. For example 100. But what about if your program just needs an array of 20 elements? You are wasting memory for nothing.
- then you program can malloc an array of x elements just when it knows the correct size of x.
Programs in memory are divided in 4 segments:
-stack (needed for call to functions)
-code (the bibary executable code)
- data (global variables/data)
- heap, in this segment you find the allocated memory.
When you decide you don't need the allocated memory anymore, you give it back to the operating system.
If you want to alloc and array of 10 integers, you do:
int *array = (int *)malloc(sizeof(int) * 10)
And then you give it back to the os with
free(array)