Where my memory is alloced, Stack or Heap, Can I find it at Run-time?
I know that memory alloced using new, gets its space in heap, and so we need to delete it before program ends, to avoid memory leak.
Let's look at this开发者_运维技巧 program...
Case 1:
char *MyData = new char[20];
_tcscpy(MyData,"Value");
.
.
.
delete[] MyData; MyData = NULL;
Case 2:
char *MyData = new char[20];
MyData = "Value";
.
.
.
delete[] MyData; MyData = NULL;
In case 2, instead of allocating value to the heap memory, it is pointing to a string literal.
Now when we do a delete it would crash, AS EXPECTED, since it is not trying to delete a heap memory. Is there a way to know where the pointer is pointing to heap or stack?
By this the programmer
- Will not try to delete any stack memory
- He can investigate why does this ponter, that was pointing to a heap memory initially, is made to refer local literals? What happened to the heap memory in the middle? Is it being made to point by another pointer and delete elsewhere and all that?
Is there a way to know where the pointer is pointing to heap or stack?
You can know this only if you remember it at the point of allocation. What you do in this case is to store your pointers in smart pointer classes and store this in the class code.
If you use boost::shared_ptr
as an example you can do this:
template<typename T> void no_delete(T* ptr) { /* do nothing here */ }
class YourDataType; // defined elsewhere
boost::shared_ptr<YourDataType> heap_ptr(new YourDataType()); // delete at scope end
YourDataType stackData;
boost::shared_ptr<YourDataType> stack_ptr(&stackData, &no_delete); // never deleted
As soon as you need that knowledge you have already lost. Why? Because then even if you omit the wrong delete[], you still have a memory leak.
The one who creates the memory should always be the one who deletes it. If at some occasion a pointer might get lost (or overwritten) then you have to keep a copy of it for the proper delete.
There is no way in Standard C++ of determining whether a pointer points to dynamically allocated memory or not. And note that string literals are not allocated on the stack.
As most of the users said here there's no standard way to discover which memory you're dealing with.
Also, as many users pointed out, it;s a kinda perverted situation where you pass a pointer to a function which should delete it automatically if it's allocated on heap.
But if you insist, nevertheless there are some ways to discover which memory belongs to which type.
You actually deal with 3 types of memory
- Stack
- Heap
- Global
For instance:
char* p = new char[10]; // p is a pointer, points to heap-allocated memory
char* p = "Hello, world!"; // p is a pointer, points to the global memory
char p[] = "Hello, world!"; // p is a buffer allocated on the stack and initialized with the string
Now let's distinguish them. I'll describe this in terms of Windows API and x86 assembler (since this is what I know :))
Let's start from stack memory.
bool IsStackPtr(PVOID pPtr)
{
// Get the stack pointer
PBYTE pEsp;
_asm {
mov pEsp, esp
};
// Query the accessible stack region
MEMORY_BASIC_INFORMATION mbi;
VERIFY(VirtualQuery(pEsp, &mbi, sizeof(mbi)));
// the accessible stack memory starts at mbi.BaseAddress and lasts for mbi.RegionSize
return (pPtr >= mbi.BaseAddress) && (pPtr < PBYTE(mbi.BaseAddress) + mbi.RegionSize);
}
If the pointer is allocated on the stack of another thread you should get its stack pointer by GetThreadContext
instead of just taking the EIP
register value.
Global memory
bool IsGlobalPtr(PVOID pPtr)
{
MEMORY_BASIC_INFORMATION mbi;
VERIFY(VirtualQuery(pPtr, &mbi, sizeof(mbi)));
// Global memory allocated (mapped) at once for the whole executable
return mbi.AllocationBase == GetModuleHandle(NULL);
}
If you're writing a DLL you should put its module handle (which is actually its base mapping pointer) instead of GetModuleHandle(NULL)
.
Heap
Theoretically you may assume that if the memory is neither global nor stack - it's allocated on heap.
But there's is actually a big ambiguity here.
You should know that there're different implementations of the heap (such as raw Windows heap accessed by HeapAlloc
/HeapFree
, or CRT-wrapped malloc
/free
or new
/delete
).
You may delete such a block via delete
operator only if you know for sure it was either stack/global pointer or it was allocated via new
.
In conclusion:
- It's a kinda pervert trick. Should not be used generally. Better to provide some extra information with the pointer which tells how to release it.
- You can only use it if you know for sure on which heap the memory was allocated (in case it's a heap memory).
I think there is no (easy) way how to tell where the memory is allocated (you might be able to determine it using a debugger, perhaps, but that is obviously not what you want). The bottom line is: never do the thing you did in case 2.
In case 2, MyData = "Value" causes a memory leak since there is no longer a reference to the memory returned from new.
There is no easy way or standard way for doing this. You can intercept the heap allocation function(s) and put each memory allocated zone in a list. Your "IsHeap" function should check if the zone passed to the function is the one from the list. This is just a hint - it is almost impossible to do this in a cross-platform manner.
But then again - why would you need that?
精彩评论