Error de segmentación en matrices de gran tamaño

8 minutos de lectura

Error de segmentacion en matrices de gran tamano
Mayak

El siguiente código me da una falla 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 4Mb. ¿Existe un límite en el tamaño de una matriz que se puede usar en C++?

Error de segmentacion en matrices de gran tamano
Carlos Salvia

Probablemente solo esté obteniendo un desbordamiento de pila aquí. La matriz es demasiado grande para caber en la región de pila de su programa; el límite de crecimiento de la pila suele ser de 8 MiB o 1 MiB para el código de espacio de usuario en la mayoría de los sistemas operativos de escritorio/servidor convencionales. (Las implementaciones normales de C++ usan la pila asm para el almacenamiento automático, es decir, nostatic matrices de variables locales. Esto hace que la desasignación se realice de forma gratuita cuando las funciones regresan o una excepción se propaga a través de ellas).

Si asigna dinámicamente la matriz, debería estar bien, suponiendo que su máquina tenga suficiente memoria.

int* array = new int[1000000];    // may throw std::bad_alloc

Pero recuerde que esto requerirá que usted delete[] la matriz manualmente para evitar pérdidas de memoria, incluso si su función sale a través de una excepción. Se desaconseja encarecidamente la creación/eliminación manual en C++ moderno, prefiera RAI.


Una mejor solución sería usar std::vector<int> array (preferencia cp). Puede reservar espacio para 1000000 elementos, si sabe cuánto crecerá. O incluso resize para que los construya por defecto (es decir, inicialice la memoria en cero, a diferencia de cuando declara una matriz simple de estilo C sin inicializador), como std::vector<int> array(1000000)

Cuando el std::vector objeto sale del alcance, su destructor desasignará el almacenamiento por usted, incluso si eso sucede a través de una excepción en una función secundaria que es capturada por una función principal.

  • Gracias por la respuesta, pero ¿podría explicarme por qué las matrices se asignan en la pila y por qué no en la memoria del programa principal?

    – Mayak

    4 de diciembre de 2009 a las 15:51

  • El código dado se asigna en la pila porque se especifica como una matriz con un número constante de elementos en tiempo de compilación. Los valores solo se colocan en el montón con malloc, new, etc.

    – Seth Johnson

    4 de diciembre de 2009 a las 16:05

  • Todas las variables automáticas se asignan en la pila. Si observa el desmontaje, verá el tamaño de sus variables locales restadas del puntero de la pila. Cuando llamas a malloc o calloc o cualquiera de las funciones de memoria, las funciones van y encuentran bloques de memoria lo suficientemente grandes como para satisfacer tu solicitud.

    – volver a ejecutar

    4 de diciembre de 2009 a las 16:12

  • @Charles, ¿por qué podríamos asignar más memoria del montón, no de 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

    24 de febrero de 2015 a las 6:58

  • @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 su requisito de tamaño. ¿Qué y dónde están la pila y el montón?

    – phuclv

    23 de junio de 2015 a las 4:45

1647638648 517 Error de segmentacion en matrices de gran tamano
Gunther piez

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 está obteniendo un desbordamiento de pila.

No lo asigne localmente en la pila, use otro lugar en su lugar. Esto se puede lograr haciendo que el objeto global o asignarlo en el global montón. 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, solo use el montón.

Esto se asignará en el segmento BSS, que forma parte del montón. Dado que está en almacenamiento estático, se inicializa en cero si no especifica lo contrario, a diferencia de las variables locales (almacenamiento automático), incluidas las matrices.

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

Un inicializador distinto de cero hará que un compilador se asigne en el segmento DATA, que también forma parte del montón. (Y todos los datos para el inicializador de la matriz ocuparán espacio en el ejecutable, incluidos todos los ceros finales implícitos, en lugar de solo un tamaño de inicialización cero en el BSS)

int c[1000000] = {1, 2, 3};
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];  // size can be a variable, unlike with static storage
   cout << "done\n";
   delete[] c;            // dynamic storage needs manual freeing
   return 0;
}

  • Si usa el tercer patrón, asignando en el montón, no olvide eliminar[] el puntero en algún momento o perderá memoria. O busca punteros inteligentes.

    – davidA

    5 de septiembre de 2012 a las 1:20

  • @meowsqueak Por supuesto que es una buena práctica delete donde sea que te alojes con new. Pero si está seguro de que asigna memoria solo una vez (como en main), no es estrictamente necesario: se garantiza que la memoria se liberará a la salida de main, incluso sin explícita. delete.

    -Gunther Piez

    5 de septiembre de 2012 a las 8:11

  • ‘at’drhirsch (¿cómo se hace un personaje de todos modos?) – sí, comentario justo. Como el OP parece nuevo en el idioma, solo quería asegurarme de que ellos, y cualquier otra persona que viera su buena respuesta, estuvieran al tanto de las implicaciones de la tercera opción si se usa en general.

    – davidA

    5 de septiembre de 2012 a las 12:19


1647638648 964 Error de segmentacion en matrices de gran tamano
RSFalcon7

Además, si está ejecutando 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 un gran poder conlleva grandes responsabilidades 🙂

  • Esta es la solución, pero aconsejo 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 colapsar. Por ejemplo, traté de ordenar una matriz con 16 000 000 elementos enteros con clasificación rápida en una máquina con 4 GB de RAM y mi sistema casi se apaga. jajaja

    – rbaleksandar

    16/10/2014 a las 16:51

  • @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?) Pruebe una implementación más consciente de la memoria;)

    – RSFalcon7

    16/10/2014 a las 23:20

  • Estoy bastante seguro de que el manejo de la matriz está bien, ya que paso por referencia y no por valor. Lo mismo sucede con bubblesort. Demonios, incluso si mi implementación de quicksort apesta bubblesort es algo que posiblemente no puedas implementar incorrectamente. jajaja

    – rbaleksandar

    17/10/2014 a las 10:07

  • LOL, podrías probar radix sort, o simplemente usar std::sort 🙂

    – RSFalcon7

    17/10/2014 a las 16:54

  • Ninguna posibilidad. Es una tarea de laboratorio. 😀

    – rbaleksandar

    17/10/2014 a las 17:00

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

Error de segmentacion en matrices de gran tamano
Narek

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

1647638649 9 Error de segmentacion en matrices de gran tamano
Pretensioso

Su matriz simple se asigna en la pila, y la pila está limitada a unos pocos magabytes, por lo tanto, su programa se desborda y se bloquea.

Probablemente lo mejor es usar montones asignados estándar::vectormatriz basada en que puede crecer casi hasta el tamaño de toda la memoria, en lugar de su matriz simple.

¡Pruébelo en línea!

#include <vector>
#include <iostream>

int main() {
   std::vector<int> c(1000000);
   std::cout << "done\n";
   return 0;
}

Luego puede acceder a los elementos de la matriz como de costumbre c[i] y/o obtener su tamaño c.size() (número de int elementos).

Si desea una matriz multidimensional con dimensiones fijas, use una combinación de ambos estándar::vector y estándar::matrizde la siguiente manera:

¡Pruébelo en línea!

#include <vector>
#include <array>
#include <iostream>

int main() {
   std::vector<std::array<std::array<int, 123>, 456>> c(100);
   std::cout << "done\n";
   return 0;
}

En el ejemplo anterior, obtiene casi el mismo comportamiento que si hubiera asignado una matriz simple int c[100][456][123]; (excepto que el vector se asigna en el montón en lugar de en la pila), puede acceder a los elementos como c[10][20][30] igual que en matriz simple. Este ejemplo anterior también asigna una matriz en el montón, lo que significa que puede tener tamaños de matriz hasta el tamaño de la memoria completa y no está limitado por el tamaño de la pila.

Para obtener el puntero al primer elemento en el vector que usa &c[0] o solo c.data().

¡Puede haber una forma más que funcionó para mí! puede reducir el tamaño de la matriz cambiando su tipo de datos:

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

o

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

¿Ha sido útil esta solución?

Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos y para mostrarte publicidad relacionada con sus preferencias en base a un perfil elaborado a partir de tus hábitos de navegación. Al hacer clic en el botón Aceptar, acepta el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Configurar y más información
Privacidad