Estoy escribiendo en C++ en una máquina con Windows en tres entornos:
Estoy trabajando con enormes conjuntos de datos y, básicamente, necesito poder dividirlos en fragmentos lo más grandes posible para manipularlos en la memoria. Para encontrar el tamaño de los bloques, imaginé algo como lo siguiente:
size_t findOptimalSize(long long beginningSize) { long long currentSize = beginningSize; while (currentSize > 0) { try { std::vector<double> v(currentSize); return currentSize; } catch (std::bad_alloc &ex) { currentSize /= 10; } } return 0; } int main() { long long size(50000000000000); try { std::vector<double> v(size); std::cout << "success" << std::endl; } catch (std::bad_alloc &ex){ std::cout << "badAlloc" << std::endl; } size_t optimal = findOptimalSize(size); std::cout << "optimal size: " + std::to_string(optimal); return 0; }El código anterior se comporta perfectamente como se esperaba en el entorno de Windows. Sin embargo, en los dos entornos de Linux, aunque siempre puede lanzar la primera excepción bad_alloc, luego hace una de dos cosas:
new no puede satisfacer la solicitud de memoria. Esto no significa necesariamente que se haya quedado sin memoria virtual. Podría deberse a una violación de la pila causada, por ejemplo, por un mal uso de los punteros o una biblioteca compartida desactualizada.
std::vector<double> v(currentSize); (Mi mejor suposición es que se acerca a la cantidad de memoria que el entorno Linux tiene disponible y se queda atascado esperando que se libere ese poco de memoria adicional para satisfacer mi solicitud)¿Hay alguna forma de lograr lo que estoy intentando y eludir estos problemas en los entornos de Linux? Supongo que los contenedores complican las cosas y enturbian mis controles de asignación simples con su lógica de gestión de memoria compleja.
¿Cómo puedo verificar si puedo asignar la memoria en estas circunstancias?
Los contenedores no tienen una lógica de administración de memoria compleja. Lo que está viendo es el resultado de una sorprendente política de Linux conocida comosobreasignación de memoria .
En Linux las grandes asignaciones no fallan; malloc() siempre tiene éxito. La memoria no se asigna realmente hasta que realmente intenta usarla. Si el sistema operativo no puede satisfacer la necesidad, invoca el asesino OOM , matando procesos hasta que libera suficiente memoria.
¿Por qué existe esto?
Una computadora Linux normalmente tiene muchos procesos heterogéneos que se ejecutan en diferentes etapas de su vida útil. Estadísticamente, en cualquier momento, no necesitan colectivamente un mapeo para cada página virtual que se les ha asignado (o se les asignará más adelante en la ejecución del programa).
Un esquema estrictamente sin compromisos excesivos crearía un mapeo estático desde páginas de direcciones virtuales a marcos de página de RAM física en el momento en que se asignan las páginas virtuales. Esto daría como resultado un sistema que puede ejecutar muchos menos programas al mismo tiempo, porque muchos marcos de página de RAM se reservarían para nada.
( fuente )
Usted puede encontrar esto ridículo. No estarías solo. Es un sistema muy controvertido. Si tu reacción inicial es "esto es estúpido", te animo a que lo leas y suspendas el juicio por un momento. En última instancia, ya sea que le guste comprometerse demasiado o no, es un hecho de la vida que todos los desarrolladores de Linux tienen que aceptar y tratar.