2017-05-17 6 views
-1

Ci-dessous est juste un exemple de code de test court pour illustrer ma question:Comment supprimer plusieurs allocations de mémoire virtuelle adjacentes avec un appel VirtualFree?

SYSTEM_INFO si; 
GetSystemInfo(&si); 

//Go by allocation granularity to have a chance to reserve adjacent memory chunks 
size_t szAlloc = si.dwAllocationGranularity; 

//Try to alloc two adjacent memory chunks 
BYTE* pp1 = (BYTE *)::VirtualAlloc(NULL, szAlloc, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); 
ASSERT(pp1); 
BYTE* pp2 = (BYTE *)::VirtualAlloc(pp1 + szAlloc, szAlloc, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); 
ASSERT(pp2); 

//We should be able to write between them 
WORD ui = 0xAB; 
BYTE* p = pp1 + szAlloc - sizeof(ui)/2; 
*(WORD*)p = ui; 

//Release both at once 
BOOL bb = ::VirtualFree(pp1, szAlloc + szAlloc, MEM_RELEASE); 
int err = ::GetLastError(); 

Comment puis-je libérer les deux morceaux de mémoire avec un appel? Ou les consolider en un morceau, si la libération à la fois n'est pas autorisée? (La raison pour laquelle je demande est parce que dans mon code actuel il peut y avoir plus que juste 2 morceaux adjacents.)

PS. Dans le code de test ci-dessus VirtualFree échoue avec le code d'erreur ERROR_INVALID_ADDRESS.

+0

L'autre problème avec votre code est qu'il n'y a aucune garantie que le deuxième morceau d'adresse –

+0

@HarryJohnston: Oui, c'est vrai, comme je l'ai dit, c'est un code de test pour illustrer concept. Dans un scénario réel, si le second bloc n'est pas disponible, je vais devoir 'VirtualAlloc' le tout et le' memcpy'. – c00000fd

Répondre

3

Vous ne pouvez pas faire exactement ce que vous voulez. Bien que je ne sache pas exactement pourquoi vous voudriez - si vous devez libérer plusieurs allocations puis les libérer tous séparément.

Cependant, je pense que vous pouvez obtenir en partie ce que vous voulez en réservant un seul gros morceau de mémoire (via auto ptr = VirtualAlloc(nullptr, ..., MEM_RESERVE, ...); puis commitng par morceaux les bits de cette allocation plus importante lorsque vous souhaitez via VirtualAlloc((uint_t*)ptr+offset, ..., MEM_COMMIT, ...);.

Si vous faites cela, alors vous pouvez libérer toute la grande réservation (y compris toutes les pièces que vous avez engagés individuellement) avec un seul appel vid VirtualFree(ptr, 0, MEM_RELEASE)

+0

Hmm. Intéressant. Mais je peux appeler 'VirtualLock (pp1, szAlloc * 2);' à travers eux très bien. La raison pour laquelle je ne peux pas «réserver» en premier est que je ne connais pas la taille initiale. L'exigence de mémoire peut augmenter avec le temps. – c00000fd

+0

Si vous utilisez une application 64 bits, il vous suffit de réserver un bloc assez grand pour la taille maximale que vous souhaitez (la réservation n'utilise pas la mémoire, elle prend simplement de l'espace d'adressage). Les applications 32 bits peuvent être plus problématiques si vous pensez que l'espace d'adressage sera insuffisant. Je ne suis pas un expert avec VirtualLock mais en regardant ses documents, il semble que cela fonctionnerait dans ce scénario. –

+0

pour * VirtualLock * important seulement que toute la gamme de la mémoire sera valide. même s'il forme des allocations différentes. mais * VirtualFree * ne peut libérer que tout ou partie de la plage de mémoire allouée (réservée). pas une autre gamme. et pour ce dont vous avez besoin * VirtualLock *? – RbMm