Où ma mémoire est ventilés entre, pile ou Tas, Puis-je trouver à Run-time?
-
24-10-2019 - |
Question
Je sais que la mémoire à l'aide de nouveaux ventilés entre, obtient son espace en tas, et nous avons donc besoin de le supprimer avant la fin du programme, afin d'éviter la fuite de mémoire.
look Let à ce programme ...
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;
Dans le cas 2, au lieu de l'attribution de la valeur au segment de mémoire, il se dirige vers un littéral de chaîne.
Maintenant, quand nous faisons une suppression, il se briserait, comme on s'y attendait, car il ne cherche pas à supprimer une mémoire de tas. Y at-il un moyen de savoir où le pointeur pointe vers tas ou la pile?
Par ce programmeur
- ne tentera pas de supprimer toute la mémoire de la pile
- Il peut enquêter sur pourquoi cette Ponter, qui pointait vers une mémoire de tas d'abord, est fait de se référer littéraux locaux? Qu'est-il arrivé à la mémoire du tas au milieu? Est-elle fait le point par un autre pointeur et supprimer ailleurs et tout cela?
La solution
Y at-il un moyen de savoir où le pointeur pointe vers tas ou la pile?
Vous pouvez savoir ce que si vous vous en souvenez au moment de l'attribution. Ce que vous faites dans ce cas est de stocker vos pointeurs dans les classes intelligentes de pointeur et le stocker dans le code de classe.
Si vous utilisez boost::shared_ptr
comme un exemple, vous pouvez faire ceci:
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
Autres conseils
Dès que vous avez besoin que les connaissances que vous avez déjà perdu. Pourquoi? Parce qu'alors, même si vous omettez la mauvaise suppression [], vous avez encore une fuite de mémoire.
Celui qui crée la mémoire doit toujours être celui qui le supprime. Si, à une occasion un pointeur peut se perdre (ou écrasées), alors vous devez garder une copie pour la bonne suppression.
Il est impossible dans la norme C ++ de déterminer si un pointeur vers la mémoire allouée dynamiquement ou non. Et notez que les littéraux de chaîne ne sont pas attribués sur la pile.
Comme la plupart des utilisateurs ont dit ici il n'y a aucun moyen standard pour découvrir quelle mémoire vous avez affaire.
En outre, comme de nombreux utilisateurs ont signalé, il;. Est une situation un peu perverti où l'on passe un pointeur vers une fonction qui devrait le supprimer automatiquement si elle est allouée sur tas
Mais si vous insistez, néanmoins il y a des façons de découvrir quelle mémoire appartient à quel type.
vous avez fait avec 3 types de mémoire
- Stack
- Heap
- Global
Par exemple:
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
Maintenant, nous allons les distinguer. Je vais vous décrire cela en termes de Windows API et assembleur x86 (puisque c'est ce que je sais:))
Le début Let de la mémoire de la pile.
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);
}
Si le pointeur est attribué sur la pile d'un autre fil que vous devriez obtenir son pointeur de pile par GetThreadContext
au lieu de simplement prendre la valeur du registre de EIP
.
mémoire globale
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);
}
Si vous écrivez une DLL vous devez mettre la poignée du module (qui est en fait son pointeur de la cartographie de base) au lieu de GetModuleHandle(NULL)
.
Heap
En théorie, vous pouvez supposer que si la mémoire est ni globale ni pile -. Il est attribué sur tas
Mais il y a est en fait une grande ambiguïté.
Vous devez savoir qu'il existe différentes implémentations du êtes des tas (comme tas brut de Windows accessible par HeapAlloc
/ HeapFree
, ou malloc
enveloppé CRT / ou free
new
/ delete
).
Vous pouvez supprimer un tel bloc par opérateur delete
que si vous êtes sûr que ce soit était pile / pointeur global ou il a été par new
alloué.
En conclusion:
- C'est un truc un peu pervers. Ne doit pas être utilisé en général. Il vaut mieux fournir des informations supplémentaires avec le pointeur qui indique comment la libérer.
- Vous ne pouvez l'utiliser si vous êtes sûr sur lequel tas la mémoire a été allouée (dans le cas où il est une mémoire de tas).
Je pense qu'il n'y a pas (facile) ainsi comment dire où la mémoire est allouée (vous pourriez être en mesure de déterminer à l'aide d'un débogueur, peut-être, mais ce n'est évidemment pas ce que vous voulez). La ligne de fond est:. Jamais faire la chose que vous avez fait dans le cas 2
Dans le cas 2, MyData = « valeur » provoque une fuite de mémoire car il n'y a plus une référence à la mémoire de retour de nouveau.
Il n'y a pas moyen facile ou moyen standard pour ce faire. Vous pouvez intercepter la fonction d'allocation de segment de mémoire (s) et de mettre chaque zone de mémoire allouée dans une liste. Votre fonction « IsHeap » doit vérifier si la zone est passé à la fonction est celle de la liste. Ceci est juste un soupçon -. Il est presque impossible de le faire d'une manière multi-plateforme
Mais là encore - pourquoi auriez-vous besoin que