Funzione VirtualAlloc2 (memoryapi.h)
Riserva, commit o modifica lo stato di un'area di memoria all'interno dello spazio indirizzi virtuale di un processo specificato (la memoria allocata viene inizializzata su zero).
Sintassi
PVOID VirtualAlloc2(
[in, optional] HANDLE Process,
[in, optional] PVOID BaseAddress,
[in] SIZE_T Size,
[in] ULONG AllocationType,
[in] ULONG PageProtection,
[in, out, optional] MEM_EXTENDED_PARAMETER *ExtendedParameters,
[in] ULONG ParameterCount
);
Parametri
[in, optional] Process
Handle di un processo. La funzione alloca memoria all'interno dello spazio indirizzi virtuale di questo processo.
L'handle deve avere il diritto di accesso PROCESS_VM_OPERATION. Per altre informazioni, vedere Process Security and Access Rights.
Se Process è NULL, la funzione alloca memoria per il processo chiamante.
[in, optional] BaseAddress
Puntatore che specifica un indirizzo iniziale desiderato per l'area delle pagine da allocare.
Se baseAddress è null, la funzione determina dove allocare l'area.
Se baseAddress non è NULL, qualsiasi struttura di MEM_ADDRESS_REQUIREMENTS fornita deve essere costituita da tutti gli zeri e l'indirizzo di base deve essere un multiplo della granularità dell'allocazione di sistema. Per determinare la granularità dell'allocazione, usare la funzione GetSystemInfo
Se questo indirizzo si trova all'interno di un enclave che non è stato inizializzato chiamando InitializeEnclave, VirtualAlloc2 alloca una pagina di zeri per l'enclave in tale indirizzo. La pagina deve essere annullata in precedenza e non verrà misurata con l'istruzione EEXTEND del modello di programmazione Intel Software Guard Extensions.
Se l'indirizzo all'interno di un enclave inizializzato, l'operazione di allocazione ha esito negativo con l'errore ERROR_INVALID_ADDRESS. Ciò vale per le enclave che non supportano la gestione dinamica della memoria (ad esempio SGX1). Le enclave SGX2 consentiranno l'allocazione e la pagina deve essere accettata dall'enclave dopo che è stata allocata.
[in] Size
Dimensioni dell'area di memoria da allocare, in byte.
Le dimensioni devono essere sempre multiple delle dimensioni della pagina.
Se baseAddress non è null, la funzione alloca tutte le pagine contenenti uno o più byte nell'intervallo compreso tra baseAddress a BaseAddress+Size. Ciò significa, ad esempio, che un intervallo a 2 byte che si allontana da un limite di pagina fa sì che la funzione allochi entrambe le pagine.
[in] AllocationType
Tipo di allocazione di memoria. Questo parametro deve contenere uno dei valori seguenti.
Valore | Significato |
---|---|
|
Alloca i costi di memoria (dalle dimensioni complessive della memoria e dei file di paging su disco) per le pagine di memoria riservate specificate. La funzione garantisce anche che quando il chiamante accede inizialmente alla memoria, il contenuto sarà zero. Le pagine fisiche effettive non vengono allocate a meno che/fino a quando non si accede effettivamente agli indirizzi virtuali.
Per riservare ed eseguire il commit delle pagine in un unico passaggio, chiamare VirtualAlloc2 con Il tentativo di eseguire il commit di un intervallo di indirizzi specifico specificando MEM_COMMIT senza MEM_RESERVE e unNULLBaseAddress ha esito negativo a meno che l'intero intervallo non sia già stato riservato. Il codice di errore risultante è ERROR_INVALID_ADDRESS. Un tentativo di eseguire il commit di una pagina già sottoposta a commit non causa l'esito negativo della funzione. Ciò significa che è possibile eseguire il commit delle pagine senza prima determinare lo stato di impegno corrente di ogni pagina. Se baseAddress specifica un indirizzo all'interno di un enclave, AllocationType deve essere MEM_COMMIT. |
|
Riserva un intervallo di spazio indirizzi virtuale del processo senza allocare alcuna risorsa di archiviazione fisica effettiva in memoria o nel file di paging su disco.
Per eseguire il commit delle pagine riservate, chiamare di nuovo VirtualAlloc2 con MEM_COMMIT. Per riservare ed eseguire il commit delle pagine in un unico passaggio, chiamare VirtualAlloc2 con Altre funzioni di allocazione della memoria, ad esempio malloc e LocalAlloc, non possono usare memoria riservata finché non viene rilasciata. |
|
Sostituisce un segnaposto con una normale allocazione privata. Sono supportate solo le visualizzazioni di sezione basate su dati/pf (nessuna immagine, memoria fisica e così via). Quando si sostituisce un segnaposto, baseAddress e dimensioni devono corrispondere esattamente a quelli del segnaposto e qualsiasi struttura MEM_ADDRESS_REQUIREMENTS fornita deve essere costituita da tutti gli zeri.
Dopo aver sostituito un segnaposto con un'allocazione privata, per liberare tale allocazione a un segnaposto, vedere il parametro Un segnaposto è un tipo di area di memoria riservata. |
|
Per creare un segnaposto, chiamare VirtualAlloc2 con MEM_RESERVE | MEM_RESERVE_PLACEHOLDER e PageProtection impostato su PAGE_NOACCESS. Per liberare/dividere/unire un segnaposto, vedere il parametro dwFreeType di VirtualFree e VirtualFreeEx.
Un segnaposto è un tipo di area di memoria riservata. |
|
Indica che i dati nell'intervallo di memoria specificato da baseAddress e dimensioni non sono più di interesse. Le pagine non devono essere lette o scritte nel file di paging. Tuttavia, il blocco di memoria verrà usato di nuovo in un secondo momento, quindi non deve essere decommesso. Questo valore non può essere utilizzato con altri valori.
L'utilizzo di questo valore non garantisce che l'intervallo utilizzato con MEM_RESET contenga zeri. Se si desidera che l'intervallo contenga zeri, decommettere la memoria e quindi ricommetterla. Quando si usa MEM_RESET, la funzione VirtualAlloc2 ignora il valore di fProtect. Tuttavia, è comunque necessario impostare fProtect su un valore di protezione valido, ad esempio PAGE_NOACCESS. VirtualAlloc2 restituisce un errore se si utilizza MEM_RESET e l'intervallo di memoria viene mappato a un file. Una visualizzazione condivisa è accettabile solo se è mappata a un file di paging. |
|
MEM_RESET_UNDO deve essere chiamato solo su un intervallo di indirizzi a cui MEM_RESET è stato applicato correttamente in precedenza. Indica che i dati nell'intervallo di memoria specificato da baseAddress e Size sono di interesse per il chiamante e tentano di invertire gli effetti di MEM_RESET. Se la funzione ha esito positivo, significa che tutti i dati nell'intervallo di indirizzi specificato sono intatti. Se la funzione ha esito negativo, almeno alcuni dei dati nell'intervallo di indirizzi sono stati sostituiti con zere.
Questo valore non può essere utilizzato con altri valori. Se MEM_RESET_UNDO viene chiamato su un intervallo di indirizzi non MEM_RESET precedente, il comportamento non è definito. Quando si specifica Windows Server 2008 R2, Windows 7, Windows Server 2008, Windows Vista, Windows Server 2003 e Windows XP: Il flag MEM_RESET_UNDO non è supportato fino a Windows 8 e Windows Server 2012. |
Questo parametro può anche specificare i valori seguenti, come indicato.
Valore | Significato |
---|---|
|
Alloca memoria usando supporto di pagine di grandi dimensioni.
Le dimensioni e l'allineamento devono essere un multiplo del minimo di pagina di grandi dimensioni. Per ottenere questo valore, usare la funzione GetLargePageMinimum. Se si specifica questo valore, è necessario specificare anche MEM_RESERVE e MEM_COMMIT. |
|
Suggerimento al sistema operativo per eseguire il mapping della memoria usando pagine 64K, se possibile.
Una pagina 64K è un'area di memoria di dimensioni pari a 64 KB, virtualmente e fisicamente contigue, e virtualmente e fisicamente allineata su un limite di 64 KB. Per impostazione predefinita, la memoria allocata tramite MEM_64K_PAGES è paginabile e le pagine fisiche che ospitano la memoria vengono allocate su richiesta (al momento dell'accesso). Se la memoria fisica è troppo frammentata per assemblare una pagina fisicamente contigua a 64.000, è possibile eseguire il mapping di una MEM_64K_PAGES allocazione utilizzando pagine di piccole dimensioni non contigue. Se MEM_64K_PAGES viene combinato con l'attributo MEM_EXTENDED_PARAMETER_NONPAGED, l'allocazione verrà mappata usando pagine 64K non di paging. In tal caso, se non è possibile ottenere pagine contigue da 64.000, l'allocazione avrà esito negativo. Se viene specificato MEM_64K_PAGES, i parametri Size e BaseAddress devono essere entrambi multipli di 64K (BaseAddress può essere NULL). |
|
Riserva un intervallo di indirizzi che può essere utilizzato per eseguire il mapping pagine delle estensioni di finestra degli indirizzi (AWE).
Questo valore deve essere usato con MEM_RESERVE e nessun altro valore. |
|
Alloca la memoria al più alto indirizzo possibile. Questo può essere più lento rispetto alle allocazioni regolari, soprattutto quando sono presenti molte allocazioni. |
[in] PageProtection
Protezione della memoria per l'area delle pagine da allocare. Se viene eseguito il commit delle pagine, è possibile specificare una delle costanti di protezione della memoria .
Se baseAddress specifica un indirizzo all'interno di un enclave, PageProtection non può essere uno dei valori seguenti:
- PAGE_NOACCESS
- PAGE_GUARD
- PAGE_NOCACHE
- PAGE_WRITECOMBINE
Quando si alloca la memoria dinamica per un enclave, il parametro PageProtection
[in, out, optional] ExtendedParameters
Puntatore facoltativo a uno o più parametri estesi di tipo MEM_EXTENDED_PARAMETER. Ognuno di questi valori di parametro estesi può avere un campo di type
[in] ParameterCount
Numero di parametri estesi a cui punta ExtendedParameters.
Valore restituito
Se la funzione ha esito positivo, il valore restituito è l'indirizzo di base dell'area allocata delle pagine.
Se la funzione ha esito negativo, il valore restituito è NULL. Per ottenere informazioni estese sull'errore, chiamare GetLastError.
Osservazioni
Questa funzione consente di specificare:
- un intervallo di spazio indirizzi virtuale e una restrizione di allineamento power-of-2 per le nuove allocazioni
- numero arbitrario di parametri estesi
- un nodo NUMA preferito per la memoria fisica come parametro esteso (vedere il parametro ExtendedParameters)
- un'operazione segnaposto (in particolare, sostituzione).
Questa API fornisce tecniche specializzate per la gestione della memoria virtuale a supporto di giochi ad alte prestazioni e applicazioni server. I segnaposto, ad esempio, consentono di partizionare in modo esplicito un intervallo di memoria riservata, sovrapponerlo e mapparlo nuovamente; può essere usato per implementare aree estendibili arbitrariamente o buffer circolari di memoria virtuale. VirtualAlloc2 consente anche di allocare memoria con un allineamento specifico della memoria.
Ogni pagina ha uno stato di pagina associato. La funzione VirtualAlloc2
- Eseguire il commit di un'area di pagine riservate
- Riservare un'area di pagine gratuite
- Riservare ed eseguire il commit simultaneo di un'area di pagine gratuite
VirtualAlloc2 può eseguire il commit di pagine già sottoposte a commit, ma non può riservare pagine già riservate. Ciò significa che è possibile eseguire il commit di un intervallo di pagine, indipendentemente dal fatto che sia già stato eseguito il commit e che la funzione non abbia esito negativo. In generale, tuttavia, è necessario specificare solo un intervallo minimo di pagine di cui non è stato eseguito il commit, perché il commit di un numero elevato di pagine già sottoposte a commit può causare la chiamata VirtualAlloc2 richiedere molto più tempo.
È possibile usare VirtualAlloc2 per riservare un blocco di pagine e quindi effettuare altre chiamate a VirtualAlloc2 per eseguire il commit di singole pagine dal blocco riservato. Ciò consente a un processo di riservare un intervallo di spazio indirizzi virtuale senza consumare spazio di archiviazione fisico fino a quando non è necessario.
Se il parametro
Per eseguire codice generato in modo dinamico, usare
La funzione VirtualAlloc2 può essere usata per riservare un'area di address windowing extensions (AWE) di memoria all'interno dello spazio indirizzi virtuale di un processo specificato. Questa area di memoria può quindi essere usata per eseguire il mapping delle pagine fisiche all'interno e all'esterno della memoria virtuale in base alle esigenze dell'applicazione. I valori
La funzione VirtualFreeEx
Quando si crea un'area eseguibile, il programma chiamante è responsabile della coerenza della cache tramite una chiamata appropriata a FlushInstructionCache una volta impostato il codice. In caso contrario, i tentativi di eseguire codice dall'area appena eseguibile possono produrre risultati imprevedibili.
Esempi
Scenario 1. Creare un buffer circolare eseguendo il mapping di due viste adiacenti della stessa sezione di memoria condivisa.
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
//
// This function creates a ring buffer by allocating a pagefile-backed section
// and mapping two views of that section next to each other. This way if the
// last record in the buffer wraps it can still be accessed in a linear fashion
// using its base VA.
//
void*
CreateRingBuffer (
unsigned int bufferSize,
_Outptr_ void** secondaryView
)
{
BOOL result;
HANDLE section = nullptr;
SYSTEM_INFO sysInfo;
void* ringBuffer = nullptr;
void* placeholder1 = nullptr;
void* placeholder2 = nullptr;
void* view1 = nullptr;
void* view2 = nullptr;
GetSystemInfo (&sysInfo);
if ((bufferSize % sysInfo.dwAllocationGranularity) != 0) {
return nullptr;
}
//
// Reserve a placeholder region where the buffer will be mapped.
//
placeholder1 = (PCHAR) VirtualAlloc2 (
nullptr,
nullptr,
2 * bufferSize,
MEM_RESERVE | MEM_RESERVE_PLACEHOLDER,
PAGE_NOACCESS,
nullptr, 0
);
if (placeholder1 == nullptr) {
printf ("VirtualAlloc2 failed, error %#x\n", GetLastError());
goto Exit;
}
//
// Split the placeholder region into two regions of equal size.
//
result = VirtualFree (
placeholder1,
bufferSize,
MEM_RELEASE | MEM_PRESERVE_PLACEHOLDER
);
if (result == FALSE) {
printf ("VirtualFreeEx failed, error %#x\n", GetLastError());
goto Exit;
}
placeholder2 = (void*) ((ULONG_PTR) placeholder1 + bufferSize);
//
// Create a pagefile-backed section for the buffer.
//
section = CreateFileMapping (
INVALID_HANDLE_VALUE,
nullptr,
PAGE_READWRITE,
0,
bufferSize, nullptr
);
if (section == nullptr) {
printf ("CreateFileMapping failed, error %#x\n", GetLastError());
goto Exit;
}
//
// Map the section into the first placeholder region.
//
view1 = MapViewOfFile3 (
section,
nullptr,
placeholder1,
0,
bufferSize,
MEM_REPLACE_PLACEHOLDER,
PAGE_READWRITE,
nullptr, 0
);
if (view1 == nullptr) {
printf ("MapViewOfFile3 failed, error %#x\n", GetLastError());
goto Exit;
}
//
// Ownership transferred, don't free this now.
//
placeholder1 = nullptr;
//
// Map the section into the second placeholder region.
//
view2 = MapViewOfFile3 (
section,
nullptr,
placeholder2,
0,
bufferSize,
MEM_REPLACE_PLACEHOLDER,
PAGE_READWRITE,
nullptr, 0
);
if (view2 == nullptr) {
printf ("MapViewOfFile3 failed, error %#x\n", GetLastError());
goto Exit;
}
//
// Success, return both mapped views to the caller.
//
ringBuffer = view1;
*secondaryView = view2;
placeholder2 = nullptr;
view1 = nullptr;
view2 = nullptr;
Exit:
if (section != nullptr) {
CloseHandle (section);
}
if (placeholder1 != nullptr) {
VirtualFree (placeholder1, 0, MEM_RELEASE);
}
if (placeholder2 != nullptr) {
VirtualFree (placeholder2, 0, MEM_RELEASE);
}
if (view1 != nullptr) {
UnmapViewOfFileEx (view1, 0);
}
if (view2 != nullptr) {
UnmapViewOfFileEx (view2, 0);
}
return ringBuffer;
}
int __cdecl wmain()
{
char* ringBuffer;
void* secondaryView;
unsigned int bufferSize = 0x10000;
ringBuffer = (char*) CreateRingBuffer (bufferSize, &secondaryView);
if (ringBuffer == nullptr) {
printf ("CreateRingBuffer failed\n");
return 0;
}
//
// Make sure the buffer wraps properly.
//
ringBuffer[0] = 'a';
if (ringBuffer[bufferSize] == 'a') {
printf ("The buffer wraps as expected\n");
}
UnmapViewOfFile (ringBuffer);
UnmapViewOfFile (secondaryView);
}
Scenario 2. Specificare un nodo NUMA preferito durante l'allocazione della memoria.
void*
AllocateWithPreferredNode (size_t size, unsigned int numaNode)
{
MEM_EXTENDED_PARAMETER param = {0};
param.Type = MemExtendedParameterNumaNode;
param.ULong = numaNode;
return VirtualAlloc2 (
nullptr, nullptr,
size,
MEM_RESERVE | MEM_COMMIT,
PAGE_READWRITE,
¶m, 1);
}
Scenario 3. Allocare memoria in un intervallo di indirizzi virtuale specifico (inferiore a 4 GB, in questo esempio) e con allineamento specifico.
void*
AllocateAlignedBelow2GB (size_t size, size_t alignment)
{
MEM_ADDRESS_REQUIREMENTS addressReqs = {0};
MEM_EXTENDED_PARAMETER param = {0};
addressReqs.Alignment = alignment;
addressReqs.HighestEndingAddress = (PVOID)(ULONG_PTR) 0x7fffffff;
param.Type = MemExtendedParameterAddressRequirements;
param.Pointer = &addressReqs;
return VirtualAlloc2 (
nullptr, nullptr,
size,
MEM_RESERVE | MEM_COMMIT,
PAGE_READWRITE,
¶m, 1);
}
Fabbisogno
Requisito | Valore |
---|---|
client minimo supportato | Windows 10 [solo app desktop] |
server minimo supportato | Windows Server 2016 [solo app desktop] |
piattaforma di destinazione | Finestre |
intestazione |
memoryapi.h (include Windows.h) |
libreria |
onecore.lib |
dll | Kernel32.dll |
Vedere anche
funzioni di gestione della memoria