Fallo de segmentación en arreglos de gran tamaño

116

El siguiente código me da un error de segmentación cuando se ejecuta en una máquina de 2 Gb, pero funciona en una máquina de 4 GB.

int main()
{
   int c[1000000];
   cout << "done\n";
   return 0;
}

El tamaño de la matriz es de solo 4 Mb. ¿Existe un límite en el tamaño de una matriz que se puede usar en c ++?

Mayank
fuente

Respuestas:

130

Probablemente solo esté obteniendo un desbordamiento de pila aquí. La matriz es demasiado grande para caber en el espacio de direcciones de la pila de su programa.

Si asigna la matriz en el montón, debería estar bien, asumiendo que su máquina tiene suficiente memoria.

int* array = new int[1000000];

Pero recuerde que esto le requerirá a delete[]la matriz. Una mejor solución sería usarlo std::vector<int>y cambiar su tamaño a 1000000 elementos.

Carlos Salvia
fuente
3
Gracias por la respuesta, pero ¿podría explicarme por qué las matrices se asignan en la pila y por qué no en la memoria principal del programa?
Mayank
18
El código dado se asigna en la pila porque se especifica como una matriz con un número constante de elementos en el momento de la compilación. Los valores solo se ponen en el montón con malloc, new, etc.
Seth Johnson
6
Todas las variables automáticas se asignan en la pila. Si observa el desmontable, verá el tamaño de sus variables locales restado del puntero de la pila. Cuando llama a malloc o calloc o cualquiera de las funciones de memoria, las funciones van y encuentran bloques de memoria lo suficientemente grandes para satisfacer su solicitud.
repetición
@Charles, ¿por qué podríamos asignar más memoria desde el montón, no desde la pila? Según tengo entendido, tanto la pila como el montón se mueven en dirección opuesta en el espacio de direcciones asignado en la memoria.
saurabh agarwal
2
@saurabhagarwal El montón no se mueve. Ni siquiera es una región de memoria contigua. El asignador simplemente devuelve un bloque de memoria libre que se ajusta a sus requisitos de tamaño ¿Qué y dónde están la pila y el montón?
phuclv
56

En C o C ++, los objetos locales generalmente se asignan en la pila. Está asignando una matriz grande en la pila, más de lo que la pila puede manejar, por lo que obtiene un stackoverflow.

No lo asigne localmente en la pila, use otro lugar en su lugar. Esto se puede lograr haciendo que el objeto sea global o asignándolo en el montón global . Las variables globales están bien, si no usa las de ninguna otra unidad de compilación. Para asegurarse de que esto no suceda por accidente, agregue un especificador de almacenamiento estático; de lo contrario, simplemente use el montón.

Esto asignará en el segmento BSS, que es parte del montón:

static int c[1000000];
int main()
{
   cout << "done\n";
   return 0;
}

Esto asignará en el segmento de DATOS, que también es parte del montón:

int c[1000000] = {};
int main()
{
   cout << "done\n";
   return 0;
}

Esto se asignará en alguna ubicación no especificada en el montón:

int main()
{
   int* c = new int[1000000];
   cout << "done\n";
   return 0;
}
Gunther Piez
fuente
Si usa el tercer patrón, asignando en el montón, no olvide eliminar [] el puntero en algún momento o perderá memoria. O busque consejos inteligentes.
davidA
8
@meowsqueak Por supuesto, es una buena práctica para deletetodos los lugares con los que asigne new. Pero si está seguro de que asigna memoria solo una vez (como en main), estrictamente no es necesario: se garantiza que la memoria se liberará a la salida de main incluso sin explícita delete.
Gunther Piez
'at'drhirsch (¿cómo se hace un carácter at de todos modos?) - sí, comentario justo. Como el OP parece nuevo en el lenguaje, solo quería asegurarme de que ellos, y cualquier otra persona que vea su buena respuesta, estén al tanto de las implicaciones de la tercera opción si se usa de manera general.
davidA
15

Además, si está ejecutando en la mayoría de los sistemas UNIX y Linux, puede aumentar temporalmente el tamaño de la pila con el siguiente comando:

ulimit -s unlimited

Pero cuidado, la memoria es un recurso limitado y con un gran poder vienen grandes responsabilidades :)

RSFalcon7
fuente
1
Esta es la solución, pero les recomiendo a todos que sean extremadamente cautelosos al eliminar estos límites predeterminados en el tamaño de la pila del programa. No solo experimentará una caída severa del rendimiento, sino que su sistema podría fallar. Por ejemplo, intenté ordenar una matriz con 16 000 000 de elementos enteros con clasificación rápida en una máquina con 4 GB de RAM y mi sistema casi se mata. LOL
rbaleksandar
@rbaleksandar Creo que su programa de ~ 16 MB casi mata su máquina porque estaba trabajando con varias copias de la matriz (¿puede ser una por llamada de función?) Intente una implementación más consciente de la memoria;)
RSFalcon7
Estoy bastante seguro de que el manejo de la matriz está bien ya que estoy pasando por referencia y no por valor. Lo mismo ocurre con Bubblesort. Demonios, incluso si mi implementación de quicksort apesta bubbleort es algo que posiblemente no puedas implementar incorrectamente. LOL
rbaleksandar
LOL, podría intentar ordenar radix, o simplemente usar std :: sort :)
RSFalcon7
1
Ninguna posibilidad. Es una tarea de laboratorio. : D
rbaleksandar
3

Su matriz se está asignando en la pila; en este caso, intente asignar una matriz del mismo tamaño utilizando alloc.

repetición
fuente
3

Porque almacena la matriz en la pila. Deberías guardarlo en el montón. Consulte este enlace para comprender el concepto de montón y pila.

Narek
fuente