I am working on a memory manager for a school assignment. The jist of the assignment is you allocate a large character array, then split that array up into blocks which the client can "allocate" or "free."
Part of the assignment involves header blocks, a little block of information before each block about the block. It basically tracks information about the block. One of the types of header blocks we need to implement is an external header block. For the external header block, instead of storing the header data in the block itself, we need to dynamically allocate a to struct with the header data. The problem is further complicated by the struct having a dynamically allocated label.
My teacher's driver is getting null when it tries to access the data, and when I delete the data, it throws an access violation, probably because I'm not storing the data in the raw memory properly.
In essence, the problem is: I need to dynamically allocate a struct with a dynamically allocated string and then put a pointer to that struct in the first 8 bytes of a block of raw memory.
Here is my current implementation
char* newString = new char[strlen(inputString)];
//Copy the label passed into this fx into the allocated memory
strcpy(newString, inputString);
//Allocate and initalize the struct
headerStruct* pHeader = new headerStruct;
pHeader->active = true;
pHeader->string = newString;
//Save the first 8 bytes of my block of memory as a headerStruct*
headerStruct* hAddress = reinterpret_cast<headerStruct(*)>(address);
//Make the first 8 bytes point to the recently allocated struct
hAddress = pHeader;
If I'm following this right, the headerLoc in you allocation needs to be a pointer to a pointer, since you need to store a pointer to the memory block at address:
MemBlockInfo** headerLoc = reinterpret_cast<MemBlockInfo **>(address);
Then dereference it properly to store header there.
Related
I have a class BLEValue that has a member called m_accumulation of type String. I use this member to accumulate the data (15000 byte) received over bluetooth until the whole data is received and then this m_accumulation will be read and the data it saves is no longer needed therefore it is set to "".
void BLEValue::addPart(uint8_t *pData, size_t length)
{
log_v("Adding part to m_accumulation. Current free heap: %d", ESP.getFreeHeap());
m_accumulation += std::string((char *)pData, length);
}
void BLEValue::clear()
{
m_accumulation = "";
m_accumulation.clear(); // I think it does the same as the previous line
}
The problem is that the memory allocated in the heap for this class member will not get free again after emptying m_accumulation. I can check this using the function ESP.getFreeHeap(). I think this is so because the object of the BLEValue class is still alive and therefore the heap memory allocated for it will be not be freed until the object is killed. Is it true?
Is there a way to empty the heap memory allocated to this String after reading its value without deleting the BLEValue object completely?
Clear marks the string as having size 0, but the internal array is not necessarily changed. To force the string to free it's memory, use shrink_to_fit after clear.
This is the first time I am trying to use std::unique_ptr but I am getting an access violation
when using std::make_unique with large size .
what is the difference in this case and is it possible to catch this type of exceptions in c++ ?
void SmartPointerfunction(std::unique_ptr<int>&Mem, int Size)
{
try
{
/*declare smart pointer */
//Mem = std::unique_ptr<int>(new int[Size]); // using new (No crash)
Mem = std::make_unique<int>(Size); // using make_unique (crash when Size = 10000!!)
/*set values*/
for (int k = 0; k < Size; k++)
{
Mem.get()[k] = k;
}
}
catch(std::exception& e)
{
std::cout << "Exception :" << e.what() << std::endl;
}
}
When you invoke std::make_unique<int>(Size), what you actually did is allocate a memory of size sizeof(int) (commonly 4bytes), and initialize it as a int variable with the number of Size. So the size of the memory you allocated is only a single int, Mem.get()[k] will touch the address which out of boundary.
But out of bounds doesn't mean your program crash immediately. As you may know, the memory address we touch in our program is virtual memory. And let's see the layout of virtual memory addresses.
You can see the memory addresses are divided into several segments (stack, heap, bss, etc). When we request a dynamic memory, the returned address will usually located in heap segment (I use usually because sometimes allocator will use mmap thus the address will located at a memory shared area, which is located between stack and heap but not marked on the diagram).
The dynamic memory we obtained are not contiguous, but heap is a contiguous segment. from the OS's point of view, any access to the heap segment is legal. And this is what the allocator exactly doing. Allocator manages the heap, divides the heap into different blocks. These blocks, some of which are marked "used" and some of which are marked "free". When we request a dynamic memory, the allocator looks for a free block that can hold the size we need, (split it to a small new block if this free block is much larger than we need), marks it as used, and returns its address. If such a free block cannot be found, the allocator will call sbrk to increase the heap.
Even if we access address which out of range, as long as it is within the heap, the OS will regard it as a legal operation. Although it might overwrite data in some used blocks, or write data into a free block. But if the address we try to access is out of the heap, for example, an address greater than program break or an address located in the bss. The OS will regard it as a "segment fault" and crash immediately.
So your program crashing is nothing to do with the parameter of std::make_unique<int>. It just so happens that when you specify 1000, the addresses you access are out of the segment.
std::make_unique<int>(Size);
This doesn't do what you are expecting!
It creates single int and initializes it into value Size!
I'm pretty sure your plan was to do:
auto p = std::make_unique<int[]>(Size)
Note extra brackets. Also not that result type is different. It is not std::unique_ptr<int>, but std::unique_ptr<int[]> and for this type operator[] is provided!
Fixed version, but IMO you should use std::vector.
I use new to allocate a buffer, as follows:
BYTE *p;
p = new BYTE[20];
If I do NOT store the size of the allocated buffer, how to determine the buffer size via p only?
You can't as p is just a pointer to the blocks of memory allocated. You have to keep count of how much memory you allocated.
You have to store the size of the allocated buffer in a variable if you want access to it later. After those statements, you'll only have access to the pointer, which can't tell you how many elements are in the buffer.
Apologies if this is a silly question - I've been self-teaching C++ and am currently writing a memory manager as an exercise for myself, but I'm not clear on what happens under the hood when I'm calling malloc and free. I've provided some skeleton code below that hopefully illustrates my question a little better.
I have overriden the global new and delete operators to call into the Alloc(size_t) and Free(void*) methods of a MemoryManager class and have set up a few memory pools that are working very well. However, I allow one of my pools to grow when it needs to. This pool is initialized by allocating some heap memory to a pointer: char* mPoolAllocator.
My question is basically: When I grow my pool, is it safe to use the same pointer (mPoolAllocator) to allocate some new heap memory? What happens when I call free(mPoolAllocator) in ~MemoryManager() below? Does the default memory manager keep track of every bit of heap memory I've allocated using this pointer and allow me to free them all in one call to free, or is it simply freeing the block beginning at the address that the pointer was last set to?
The code below is only an illustration and is nowhere near to how my MemoryManager class works: I'm primarily looking for feedback on malloc() and free().
.....................................................................................................................................................................
class MemoryManager
class MemoryManager
{
public:
MemoryManager();
~MemoryManager();
void* Alloc(size_t size);
void Free(void* address);
private:
size_t mFreeMemory; // unallocated memory left
char* mPoolAllocator, // used to alloc memory from the heap
* mUnallocated; // points to front of free blocks linked list
void ExtendPool(); // extends pool, increasing available memory
void* GetBlock(size_t size); // returns heap address sufficient for and object of size
}
.
void* MemoryManager::Alloc(size_t size)
{
/* If there is free memory */
if(size <= mFreeMemory)
{
return GetBlock(size);
}
else // else create new free memory
{
ExtendPool();
return GetBlock(size);
}
}
.
void MemoryManager::ExtendPool()
{
mPoolAllocator = (char*)malloc(POOL_EXTEND_SIZE);
// some calls to functions that split the extended pool into blocks
mUnallocated = mPoolAllocator; // point to the next unallocated memory block (beginning of extended pool)
}
.
MemoryManager::~MemoryManager()
{
free(mPoolAllocator);
}
No, that leaks memory.
Each return value from malloc() must be used as an argument in a distinct call tofree(). For this usage, look into realloc() which will make it work more like you expect, since it allows you to grow an already-allocated piece of heap memory.
There is no trace in the mPoolAllocator variable of the previous pointers returned from malloc().
Also, in C++, shouldn't you use new[] to allocate arrays of bytes?
If I declare a data structure globally in a C++ application , does it consume stack memory or heap memory ?
For eg
struct AAA
{
.../.../.
../../..
}arr[59652323];
Since I wasn't satisfied with the answers, and hope that the sameer karjatkar wants to learn more than just a simple yes/no answer, here you go.
Typically a process has 5 different areas of memory allocated
Code - text segment
Initialized data – data segment
Uninitialized data – bss segment
Heap
Stack
If you really want to learn what is saved where then read and bookmark these:
COMPILER, ASSEMBLER, LINKER AND LOADER: A BRIEF STORY (look at Table w.5)
Anatomy of a Program in Memory
The problem here is the question. Let's assume you've got a tiny C(++ as well, they handle this the same way) program like this:
/* my.c */
char * str = "Your dog has fleas."; /* 1 */
char * buf0 ; /* 2 */
int main(){
char * str2 = "Don't make fun of my dog." ; /* 3 */
static char * str3 = str; /* 4 */
char * buf1 ; /* 5 */
buf0 = malloc(BUFSIZ); /* 6 */
buf1 = malloc(BUFSIZ); /* 7 */
return 0;
}
This is neither allocated on the stack NOR on the heap. Instead, it's allocated as static data, and put into its own memory segment on most modern machines. The actual string is also being allocated as static data and put into a read-only segment in right-thinking machines.
is simply a static allocated pointer; room for one address, in static data.
has the pointer allocated on the stack and will be effectively deallocated when main returns. The string, since it's a constant, is allocated in static data space along with the other strings.
is actually allocated exactly like at 2. The static keyword tells you that it's not to be allocated on the stack.
...but buf1 is on the stack, and
... the malloc'ed buffer space is on the heap.
And by the way., kids don't try this at home. malloc has a return value of interest; you should always check the return value.
For example:
char * bfr;
if((bfr = malloc(SIZE)) == NULL){
/* malloc failed OMG */
exit(-1);
}
Usually it consumes neither. It tries to allocate them in a memory segment which is likely to remain constant-size for the program execution. It might be bss, stack, heap or data.
Neither. It is .data section.
Global memory is pre-allocated in a fixed memory block, or on the heap, depending on how it is allocated by your application:
byte x[10]; // pre-allocated by the compiler in some fixed memory block
byte *y
main()
{
y = malloc(10); // allocated on the heap
}
EDIT:
The question is confusing: If I allocate a data structure globally in a C++ application , does it consume stack memory or heap memory ?
"allocate"? That could mean many things, including calling malloc(). It would have been different if the question was "if I declare and initialize a data structure globally".
Many years ago, when CPUs were still using 64K segments, some compilers were smart enough to dynamically allocate memory from the heap instead of reserving a block in the .data segment (because of limitations in the memory architecture).
I guess I'm just too old....
Neither declaring a data structure globally in a C++ consumes heap or stack memory. Actually, global variables are typically allocated in a data segment whose size remains unchanged during the whole program. Stacks and heaps are typically used for variables that get created and destroyed during executing the program.
The global object itself will take up memory that the runtime or compiler reserves for it before main is executed, this is not a variable runtime cost so neither stack nor heap.
If the ctor of the object allocates memory it will be in the heap, and any subsequent allocations by the object will be heap allocations.
It depends on the exact nature of the global object, if it's a pointer or the whole object itself that is global.
global variables live on the heap. these are a special case because they live for the life of the program
If you are explicitly allocating the memory yourself by new or malloc, then it will be allocated in heap. If the compiler is allocating the memory, then it will be allocated on stack.