Catatan
Akses ke halaman ini memerlukan otorisasi. Anda dapat mencoba masuk atau mengubah direktori.
Akses ke halaman ini memerlukan otorisasi. Anda dapat mencoba mengubah direktori.
Mencadangkan, menerapkan, atau mengubah status wilayah memori dalam ruang alamat virtual dari proses tertentu (memori yang dialokasikan diinisialisasi menjadi nol).
Sintaksis
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
);
Parameter
[in, optional] Process
Handel ke proses. Fungsi ini mengalokasikan memori dalam ruang alamat virtual proses ini.
Handel harus memiliki akses PROCESS_VM_OPERATION yang tepat. Untuk informasi selengkapnya, lihat Keamanan Proses dan Hak Akses.
Jika ProsesNULL, fungsi mengalokasikan memori untuk proses panggilan.
[in, optional] BaseAddress
Penunjuk yang menentukan alamat awal yang diinginkan untuk wilayah halaman yang ingin Anda alokasikan.
Jika BaseAddressadalah NULL, fungsi menentukan tempat untuk mengalokasikan wilayah.
Jika BaseAddress bukan NULL, maka struktur MEM_ADDRESS_REQUIREMENTS yang disediakan harus terdiri dari semua nol, dan alamat dasar harus kelipatan granularitas alokasi sistem. Untuk menentukan granularitas alokasi, gunakan fungsi GetSystemInfo .
Jika alamat ini berada dalam enklave yang belum Anda inisialisasi dengan memanggil InitializeEnclave, VirtualAlloc2 mengalokasikan halaman nol untuk enklave di alamat tersebut. Halaman sebelumnya harus tidak dikomit, dan tidak akan diukur dengan instruksi EEXTEND dari model pemrograman Intel Software Guard Extensions.
Jika alamat berada dalam enklave yang Anda inisialisasi, maka operasi alokasi gagal dengan kesalahan ERROR_INVALID_ADDRESS . Itu berlaku untuk enklave yang tidak mendukung manajemen memori dinamis (yaitu SGX1). Enklave SGX2 akan mengizinkan alokasi, dan halaman harus diterima oleh enklave setelah dialokasikan.
[in] Size
Ukuran wilayah memori yang akan dialokasikan, dalam byte.
Ukuran harus selalu kelipatan ukuran halaman.
Jika BaseAddress bukan NULL, fungsi mengalokasikan semua halaman yang berisi satu atau beberapa byte dalam rentang dari BaseAddress ke Ukuran BaseAddress+. Ini berarti, misalnya, bahwa rentang 2 byte yang melekat pada batas halaman menyebabkan fungsi mengalokasikan kedua halaman.
[in] AllocationType
Jenis alokasi memori. Parameter ini harus berisi salah satu nilai berikut.
| Nilai | Arti |
|---|---|
|
Mengalokasikan biaya memori (dari ukuran keseluruhan memori dan file halaman pada disk) untuk halaman memori cadangan yang ditentukan. Fungsi ini juga menjamin bahwa ketika penelepon awalnya mengakses memori, kontennya akan menjadi nol. Halaman fisik aktual tidak dialokasikan kecuali/sampai alamat virtual benar-benar diakses.
Untuk memesan dan menerapkan halaman dalam satu langkah, panggil VirtualAlloc2 dengan Mencoba menerapkan rentang alamat tertentu dengan menentukan MEM_COMMIT tanpa MEM_RESERVE dan BaseAddressnon-NULL gagal kecuali seluruh rentang telah dicadangkan. Kode kesalahan yang dihasilkan ERROR_INVALID_ADDRESS. Upaya untuk menerapkan halaman yang sudah diterapkan tidak menyebabkan fungsi gagal. Ini berarti Anda dapat menerapkan halaman tanpa terlebih dahulu menentukan status komitmen saat ini dari setiap halaman. Jika BaseAddress menentukan alamat dalam enklave, AllocationType harus MEM_COMMIT. |
|
Mencadangkan berbagai ruang alamat virtual proses tanpa mengalokasikan penyimpanan fisik aktual dalam memori atau dalam file halaman pada disk.
Anda menerapkan halaman yang dipesan dengan memanggil VirtualAlloc2 lagi dengan MEM_COMMIT. Untuk memesan dan menerapkan halaman dalam satu langkah, panggil VirtualAlloc2 dengan Fungsi alokasi memori lainnya, seperti malloc dan LocalAlloc, tidak dapat menggunakan memori cadangan hingga dirilis. |
|
Mengganti tempat penampung dengan alokasi privat normal. Hanya tampilan bagian yang didukung data/pf yang didukung (tidak ada gambar, memori fisik, dll.). Ketika Anda mengganti tempat penampung, BaseAddress dan Ukuran harus sama persis dengan tempat penampung, dan struktur MEM_ADDRESS_REQUIREMENTS yang disediakan harus terdiri dari semua nol.
Setelah Anda mengganti tempat penampung dengan alokasi privat, untuk membebaskan alokasi tersebut kembali ke tempat penampung, lihat parameter dwFreeTypevirtualFree dan VirtualFreeEx. Tempat penampung adalah jenis wilayah memori yang dipesan. |
|
Untuk membuat tempat penampung, panggil VirtualAlloc2 dengan MEM_RESERVE | MEM_RESERVE_PLACEHOLDER dan PageProtection diatur ke PAGE_NOACCESS. Untuk membebaskan/membagi/menyatukan tempat penampung, lihat parameter dwFreeType dari VirtualFree dan VirtualFreeEx.
Tempat penampung adalah jenis wilayah memori yang dipesan. |
|
Menunjukkan bahwa data dalam rentang memori yang ditentukan oleh BaseAddress dan Ukuran tidak lagi menarik. Halaman tidak boleh dibaca dari atau ditulis ke file halaman. Namun, blok memori akan digunakan lagi nanti, sehingga tidak boleh dinonaktifkan. Nilai ini tidak dapat digunakan dengan nilai lain.
Menggunakan nilai ini tidak menjamin bahwa rentang yang dioperasikan dengan MEM_RESET akan berisi nol. Jika Anda ingin rentang berisi nol, nonaktifkan memori lalu kirim ulang. Saat Anda menggunakan MEM_RESET, fungsi VirtualAlloc2 mengabaikan nilai fProtect. Namun, Anda masih harus mengatur fProtect ke nilai perlindungan yang valid, seperti PAGE_NOACCESS. VirtualAlloc2 mengembalikan kesalahan jika Anda menggunakan MEM_RESET dan rentang memori dipetakan ke file. Tampilan bersama hanya dapat diterima jika dipetakan ke file halaman. |
|
MEM_RESET_UNDO hanya boleh dipanggil pada rentang alamat yang MEM_RESET berhasil diterapkan sebelumnya. Ini menunjukkan bahwa data dalam rentang memori yang ditentukan oleh BaseAddress dan Ukuran menarik bagi pemanggil dan mencoba membalikkan efek MEM_RESET. Jika fungsi berhasil, itu berarti semua data dalam rentang alamat yang ditentukan utuh. Jika fungsi gagal, setidaknya beberapa data dalam rentang alamat telah diganti dengan nol.
Nilai ini tidak dapat digunakan dengan nilai lain. Jika MEM_RESET_UNDO dipanggil pada rentang alamat yang tidak MEM_RESET sebelumnya, perilaku tersebut tidak ditentukan. Saat Anda menentukan MEM_RESET, fungsi VirtualAlloc2 mengabaikan nilai PageProtection. Namun, Anda masih harus mengatur PageProtection ke nilai perlindungan yang valid, seperti PAGE_NOACCESS. Windows Server 2008 R2, Windows 7, Windows Server 2008, Windows Vista, Windows Server 2003 dan Windows XP: Bendera MEM_RESET_UNDO tidak didukung hingga Windows 8 dan Windows Server 2012. |
Parameter ini juga dapat menentukan nilai berikut seperti yang ditunjukkan.
| Nilai | Arti |
|---|---|
|
Mengalokasikan memori menggunakan dukungan halaman besar.
Ukuran dan perataan harus kelipatan minimum halaman besar. Untuk mendapatkan nilai ini, gunakan fungsi GetLargePageMinimum . Jika Anda menentukan nilai ini, Anda juga harus menentukan MEM_RESERVE dan MEM_COMMIT. |
|
Petunjuk ke sistem operasi untuk memetakan memori menggunakan halaman 64K, jika memungkinkan.
Halaman 64K adalah wilayah memori berukuran 64K, berdekatan secara virtual dan fisik, serta secara virtual dan fisik selaras pada batas 64K. Secara default, memori yang dialokasikan menggunakan MEM_64K_PAGES dapat halaman, dan halaman fisik yang mendukung memori dialokasikan sesuai permintaan (pada saat akses). Jika memori fisik terlalu terfragmentasi untuk merakit halaman 64K yang berdampingan secara fisik, semua atau bagian dari alokasi MEM_64K_PAGES dapat dipetakan menggunakan halaman kecil yang tidak berdampingan sebagai gantinya. Jika MEM_64K_PAGES dikombinasikan dengan atribut MEM_EXTENDED_PARAMETER_NONPAGED , alokasi akan dipetakan menggunakan halaman 64K non-halaman. Dalam hal ini, jika halaman 64K yang bersebelahan tidak dapat diperoleh, alokasi akan gagal. Jika MEM_64K_PAGES ditentukan, parameter Ukuran dan BaseAddress keduanya harus kelipatan 64K (BaseAddress mungkin NULL). |
|
Mencadangkan rentang alamat yang dapat digunakan untuk memetakan halaman Ekstensi Jendela Alamat (AWE).
Nilai ini harus digunakan dengan MEM_RESERVE dan tidak ada nilai lain. |
|
Mengalokasikan memori pada alamat setinggi mungkin. Ini bisa lebih lambat daripada alokasi biasa, terutama ketika ada banyak alokasi. |
[in] PageProtection
Perlindungan memori untuk wilayah halaman yang akan dialokasikan. Jika halaman sedang diterapkan, Anda dapat menentukan salah satu konstanta perlindungan memori.
Jika BaseAddress menentukan alamat dalam enklave, PageProtection tidak boleh menjadi salah satu nilai berikut:
- PAGE_NOACCESS
- PAGE_GUARD
- PAGE_NOCACHE
- PAGE_WRITECOMBINE
Saat mengalokasikan memori dinamis untuk enklave, parameter PageProtection harus PAGE_READWRITE atau PAGE_EXECUTE_READWRITE.
[in, out, optional] ExtendedParameters
Penunjuk opsional ke satu atau beberapa parameter jenis MEM_EXTENDED_PARAMETER yang diperluas. Masing-masing nilai parameter yang diperluas tersebut dapat memiliki bidang Jenisdari MemExtendedParameterAddressRequirements atau MemExtendedParameterNumaNode. Jika tidak ada parameter perluasan MemExtendedParameterNumaNode yang disediakan, maka perilakunya sama dengan untuk fungsi VirtualAlloc/MapViewOfFile (yaitu, simpul NUMA pilihan untuk halaman fisik ditentukan berdasarkan prosesor ideal utas yang pertama kali mengakses memori).
[in] ParameterCount
Jumlah parameter yang diperluas yang diacu oleh ExtendedParameters.
Mengembalikan nilai
Jika fungsi berhasil, nilai pengembalian adalah alamat dasar dari wilayah halaman yang dialokasikan.
Jika fungsi gagal, nilai yang dikembalikan adalah NULL. Untuk mendapatkan informasi kesalahan yang diperluas, hubungi GetLastError.
Komentar
Fungsi ini memungkinkan Anda menentukan:
- berbagai ruang alamat virtual dan pembatasan perataan power-of-2 untuk alokasi baru
- jumlah parameter yang diperluas secara arbitrer
- simpul NUMA pilihan untuk memori fisik sebagai parameter yang diperluas (lihat parameter ExtendedParameters )
- operasi tempat penampung (khususnya, penggantian).
API ini menyediakan teknik khusus untuk mengelola memori virtual untuk mendukung game berkinerja tinggi dan aplikasi server. Misalnya, tempat penampung memungkinkan rentang memori yang dipesan secara eksplisit dipartisi, dilapisi, dan dipetakan ulang; ini dapat digunakan untuk mengimplementasikan wilayah yang dapat diperluas secara arbitrer atau buffer cincin memori virtual. VirtualAlloc2 juga memungkinkan untuk mengalokasikan memori dengan penyelarasan memori tertentu.
Setiap halaman memiliki status halaman terkait. Fungsi VirtualAlloc2 dapat melakukan operasi berikut:
- Menerapkan wilayah halaman yang dipesan
- Memesan wilayah halaman gratis
- Secara bersamaan memesan dan menerapkan wilayah halaman gratis
VirtualAlloc2 dapat menerapkan halaman yang sudah diterapkan, tetapi tidak dapat memesan halaman yang sudah dicadangkan. Ini berarti Anda dapat menerapkan rentang halaman, terlepas dari apakah halaman tersebut telah diterapkan, dan fungsi tidak akan gagal. Namun, secara umum, hanya rentang minimal dari sebagian besar halaman yang tidak dikomit harus ditentukan, karena menerapkan sejumlah besar halaman yang sudah diterapkan dapat menyebabkan panggilan VirtualAlloc2 memakan waktu lebih lama.
Anda dapat menggunakan VirtualAlloc2 untuk memesan blok halaman lalu melakukan panggilan tambahan ke VirtualAlloc2 untuk menerapkan halaman individual dari blok yang dipesan. Ini memungkinkan proses untuk memesan berbagai ruang alamat virtualnya tanpa mengkonsumsi penyimpanan fisik sampai diperlukan.
Jika parameter lpAddress bukan NULL, fungsi menggunakan parameter lpAddress dan dwSize untuk menghitung wilayah halaman yang akan dialokasikan. Status seluruh rentang halaman saat ini harus kompatibel dengan jenis alokasi yang ditentukan oleh parameter flAllocationType . Jika tidak, fungsi gagal dan tidak ada halaman yang dialokasikan. Persyaratan kompatibilitas ini tidak menghalangi penerapan halaman yang sudah dilakukan; lihat daftar sebelumnya.
Untuk menjalankan kode yang dihasilkan secara dinamis, gunakan VirtualAlloc2 untuk mengalokasikan memori, dan fungsi VirtualProtectEx untuk memberikan akses PAGE_EXECUTE .
Fungsi VirtualAlloc2 dapat digunakan untuk memesan wilayah memori Address Windowing Extensions (AWE) dalam ruang alamat virtual dari proses tertentu. Wilayah memori ini kemudian dapat digunakan untuk memetakan halaman fisik ke dalam dan kehabisan memori virtual seperti yang diperlukan oleh aplikasi. Nilai MEM_PHYSICAL dan MEM_RESERVE harus diatur dalam parameter AllocationType . Nilai MEM_COMMIT tidak boleh diatur. Perlindungan halaman harus diatur ke PAGE_READWRITE.
Fungsi VirtualFreeEx dapat menonaktifkan halaman berkomitmen, merilis penyimpanan halaman, atau secara bersamaan dapat menonaktifkan dan merilis halaman yang diterapkan. Ini juga dapat merilis halaman yang dipesan, menjadikannya halaman gratis.
Saat membuat wilayah yang akan dapat dieksekusi, program panggilan bertanggung jawab untuk memastikan koherensi cache melalui panggilan yang sesuai ke FlushInstructionCache setelah kode ditetapkan. Jika tidak, upaya untuk mengeksekusi kode keluar dari wilayah yang baru dapat dieksekusi dapat menghasilkan hasil yang tidak dapat diprediksi.
Contoh
Skenario 1. Buat buffer melingkar dengan memetakan dua tampilan yang berdekatan dari bagian memori bersama yang sama.
#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);
}
Skenario 2. Tentukan simpul NUMA pilihan saat mengalokasikan memori.
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);
}
Skenario 3. Alokasikan memori dalam rentang alamat virtual tertentu (di bawah 4GB, dalam contoh ini) dan dengan perataan tertentu.
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);
}
Persyaratan
| Syarat | Nilai |
|---|---|
| Klien minimum yang didukung | Windows 10 [hanya aplikasi desktop] |
| server minimum yang didukung | Windows Server 2016 [hanya aplikasi desktop] |
| Target Platform | Windows |
| Header | memoryapi.h (termasuk Windows.h) |
| Library | onecore.lib |
| DLL | Kernel32.dll |