Como se ha mencionado, no parece ser posible liberar parcialmente un rango de páginas reservadas porque los VirtualFree()
documentation estados:
VirtualFree()
es en sí mismo una envoltura delgada de la función de kernel NtFreeVirtualMemory()
. Its documentation page (lo mismo que para ZwFreeVirtualMemory()
) también tiene esta fraseología.
Una solución posible es dividir una única reserva grande con varias más pequeñas. Por ejemplo, supongamos que normalmente reserva 8 MiB de espacio de direcciones virtuales a la vez. En cambio, podría intentar reservar el rango en treinta y dos reservas contiguas de 256 KiB. La primera reserva 256 KiB contendría un campo de bits sin signo de 32 bits, donde el iº bit se establece si el iº se obtuvo reserva 256 KiB: salida
#define NOMINMAX
#include <windows.h>
#include <assert.h>
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#define RESERVATION_SIZE (256*1024)
typedef struct st_first_reservation {
size_t reservation_size;
uint32_t rfield;
char premaining[0];
} st_first_reservation;
int main()
{
SYSTEM_INFO sys_info = { 0 };
GetSystemInfo(&sys_info);
assert((RESERVATION_SIZE % sys_info.dwPageSize) == 0);
void *vp = VirtualAlloc(NULL, 32*RESERVATION_SIZE, MEM_RESERVE, PAGE_NOACCESS);
if (VirtualFree(vp, 0, MEM_RELEASE) == 0) {
fprintf(stderr, "Error: VirtualFree() failed.\n");
return EXIT_FAILURE;
}
st_first_reservation *pfirst_reservation = (st_first_reservation *) VirtualAlloc(vp, RESERVATION_SIZE, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
if (pfirst_reservation == NULL) {
pfirst_reservation = (st_first_reservation *) VirtualAlloc(NULL, RESERVATION_SIZE, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
if (pfirst_reservation == NULL) {
fprintf(stderr, "Error: VirtualAlloc() failed.\n");
return EXIT_FAILURE;
}
}
fprintf(stderr, "pfirst_reservation = 0x%p\n", (void *) pfirst_reservation);
pfirst_reservation->reservation_size = RESERVATION_SIZE;
pfirst_reservation->rfield = 1LU;
char *p = (char *) pfirst_reservation;
unsigned i = 1;
for (; i < 32; ++i) {
vp = VirtualAlloc(p += RESERVATION_SIZE, RESERVATION_SIZE, MEM_RESERVE, PAGE_NOACCESS);
if (vp != NULL) {
assert(((void *) vp) == p);
pfirst_reservation->rfield |= 1LU << i;
fprintf(stderr, "Obtained reservation #%u\n", i + 1);
} else {
fprintf(stderr, "Failed to obtain reservation #%u\n", i + 1);
}
}
fprintf(stderr, "pfirst_reservation->rfield = 0x%08x\n", pfirst_reservation->rfield);
return EXIT_SUCCESS;
}
muestra:
pfirst_reservation = 0x009A0000
Obtained reservation #2
Obtained reservation #3
Obtained reservation #4
Obtained reservation #5
Obtained reservation #6
Obtained reservation #7
Obtained reservation #8
Obtained reservation #9
Obtained reservation #10
Obtained reservation #11
Obtained reservation #12
Obtained reservation #13
Obtained reservation #14
Obtained reservation #15
Obtained reservation #16
Obtained reservation #17
Obtained reservation #18
Obtained reservation #19
Obtained reservation #20
Obtained reservation #21
Obtained reservation #22
Obtained reservation #23
Obtained reservation #24
Obtained reservation #25
Obtained reservation #26
Obtained reservation #27
Obtained reservation #28
Obtained reservation #29
Obtained reservation #30
Obtained reservation #31
Obtained reservation #32
pfirst_reservation->rfield = 0xffffffff
EDIT: he descubierto que es mucho mejor "pre-reserva" los treinta y dos 256 KiB oscila todos a la vez, gratis, y TH Trate de volver a reservar tantas como pueda.
He actualizado el código y la salida de muestra anterior.
En un entorno multiproceso, el código puede volver a la asignación de "lugar en cualquier lugar" de la primera reserva. Tal vez es una buena idea intentar reservar RESERVATION_SIZE
bytes en un rango reservado-luego-liberado de 32*RESERVATION_SIZE
bytes cinco o más veces, volviendo finalmente a la asignación de "colocar en cualquier lugar".
El objetivo de la memoria virtual es abstraer todo esto y dejar que el kernel se ocupe de la ubicación de la memoria. –
¿Necesita su aplicación liberar páginas de memoria virtual? ¿Se está quedando sin espacio de direcciones virtuales? –
@DanielTrebbien: La situación es la siguiente ... Necesito una nueva región, así que intento asignarla a VirtualAlloc. Sin embargo, VirtualAlloc arroja una falta de memoria. Al mismo tiempo, debido a algunos metadatos que me mantengo, sé que ciertas regiones están medio llenas. Ahora me gustaría reducir o reasignar esas regiones a bajo costo hasta que vuelva a tener memoria. – cib