¿Es posible asignar una gran cantidad de memoria virtual en Linux?
Posiblemente. Pero es posible que deba configurarlo para que se permita:
El kernel de Linux admite los siguientes modos de manejo de compromiso excesivo
0 - Manejo heurístico de compromiso excesivo. Se rechazan los compromisos excesivos obvios del espacio de direcciones. Se utiliza para un sistema típico. Garantiza que una asignación seriamente salvaje falle al tiempo que permite un compromiso excesivo para reducir el uso de intercambio. root puede asignar un poco más de memoria en este modo. Este es el valor predeterminado.
1 - Comprometerse siempre en exceso. Apropiado para algunas aplicaciones científicas. Un ejemplo clásico es el código que usa arreglos dispersos y solo depende de la memoria virtual que consiste casi en su totalidad en cero páginas.
2 - No te comprometas demasiado. No se permite que la asignación de espacio de direcciones total para el sistema exceda el intercambio + una cantidad configurable (el valor predeterminado es 50 %) de RAM física. Dependiendo de la cantidad que use, en la mayoría de las situaciones esto significa que un proceso no se eliminará mientras accede a las páginas, pero recibirá errores en la asignación de memoria según corresponda.
Útil para aplicaciones que quieren garantizar que sus asignaciones de memoria estarán disponibles en el futuro sin tener que inicializar cada página.
La política de compromiso excesivo se establece a través de sysctl `vm.overcommit_memory'.
Entonces, si desea asignar más memoria virtual de la que tiene memoria física, entonces querrá:
# in shell
sysctl -w vm.overcommit_memory=1
RLIMIT_AS El tamaño máximo de la memoria virtual del proceso (espacio de direcciones) en bytes. Este límite afecta a las llamadas a brk(2), mmap(2) y mremap(2), que fallan con el error ENOMEM al superar este límite. Además, la expansión automática de la pila fallará (y generará un SIGSEGV que eliminará el proceso si no se ha puesto a disposición una pila alternativa a través de sigaltstack(2)). Dado que el valor es largo, en máquinas con un largo de 32 bits, este límite es como máximo de 2 GiB o este recurso es ilimitado.
Entonces, querrías:
setrlimit(RLIMIT_AS, {
.rlim_cur = RLIM_INFINITY,
.rlim_max = RLIM_INFINITY,
});
O bien, si no puede otorgar permiso al proceso para hacer esto, puede configurarlo de forma persistente en /etc/security/limits.conf, lo que afectará a todos los procesos (de un usuario/grupo).
Ok, parece que mmap es compatible... pero requiere un descriptor de archivo. ... podría ser una victoria, pero no si tienen que estar respaldados por un archivo... No me gusta la idea de adjuntar a un archivo
No necesita usar un archivo mmap respaldado. Hay MAP_ANONYMOUS para eso.
No sabía qué número poner para solicitar
Luego usa nulo. Ejemplo:
mmap(nullptr, 256*GB, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0)
Dicho esto, si configuró el sistema como se describe, entonces new
debería funcionar tan bien como mmap
. Probablemente usará malloc
que probablemente usará mmap
para asignaciones grandes como esta.
Sugerencia adicional:puede beneficiarse al aprovechar las ventajas del uso de páginas HugeTLB.
El valor de 256*GB
no encaja en un rango de tipo entero de 32 bits. Prueba uint64_t
como un tipo de GB
:
constexpr uint64_t GB = 1024*1024*1024;
o, alternativamente, fuerza la multiplicación de 64 bits:
char* p = new char[256ULL * GB];
OT:Preferiría esta definición de GB
:
constexpr uint64_t GB = 1ULL << 30;
En cuanto al límite de memoria virtual, consulte esta respuesta.