¿Por qué debería usar malloc () cuando & # 8220; char bigchar [1u < < 31 - 1]; & # 8221; funciona bien?

StackOverflow https://stackoverflow.com/questions/839291

  •  22-07-2019
  •  | 
  •  

Pregunta

¿Cuál es la ventaja de usar malloc (además del retorno NULL en caso de falla) sobre los arreglos estáticos? El siguiente programa consumirá todo mi carnero y comenzará a llenar el intercambio solo si los bucles no están comentados. No se bloquea.

...

#include <stdio.h>

unsigned int bigint[ 1u << 29 - 1 ];
unsigned char bigchar[ 1u << 31 - 1 ];

int main (int argc, char **argv) {
  int i;
/*   for (i = 0; i < 1u << 29 - 1; i++) bigint[i] = i; */
/*   for (i = 0; i < 1u << 31 - 1; i++) bigchar[i] = i & 0xFF; */

  getchar();
  return 0;
}

...

Después de algunas pruebas y errores, descubrí que lo anterior es la matriz estática más grande permitida en mi máquina Intel de 32 bits con GCC 4.3. ¿Es este un límite estándar, un límite de compilador o un límite de máquina? Aparentemente puedo tener tantos de ellos como quiera. Segfault, pero solo si pido (y trato de usar) más de lo que malloc me daría de todos modos.

¿Hay alguna manera de determinar si una matriz estática fue realmente asignada y segura de usar?

EDITAR: Me interesa saber por qué se usa malloc para administrar el montón en lugar de dejar que el sistema de memoria virtual lo maneje. Aparentemente, puedo dimensionar una matriz muchas veces más de lo que creo que necesitaré y el sistema de memoria virtual solo mantendrá en RAM lo que se necesita. Si nunca escribo, p. Al final (o principio) de estas grandes matrices, el programa no utiliza la memoria física. Además, si puedo escribir en cada ubicación, ¿qué hace malloc además de incrementar un puntero en el montón o buscar asignaciones anteriores en el mismo proceso?

Nota del editor: 1 < < 31 provoca un comportamiento indefinido si int es 32 bits, por lo que he modificado la pregunta para leer 1u . La intención de la pregunta es preguntar sobre la asignación de grandes buffers estáticos.

¿Fue útil?

Solución

Bueno, por dos razones realmente:

  1. Debido a la portabilidad, ya que algunos sistemas no administrarán la memoria virtual por usted.

  2. Necesitarás inevitablemente dividir esta matriz en trozos más pequeños para que sea útil, luego para realizar un seguimiento de todos los trozos, y eventualmente a medida que comienzas a "liberar". algunos de los fragmentos de la matriz que ya no necesita, tendrá el problema de fragmentación de memoria .

En general, terminará implementando una gran cantidad de funcionalidades de administración de memoria (en realidad prácticamente reimplementando el malloc) sin el beneficio de la portabilidad.

De ahí las razones:

  • Portabilidad de código mediante encapsulación y estandarización de gestión de memoria.

  • Mejora de la productividad personal mediante la reutilización de código.

Otros consejos

con malloc puede aumentar y reducir su matriz: se vuelve dinámica, por lo que puede asignar exactamente lo que necesita.

Esto se llama gestión de memoria personalizada, supongo. Puede hacerlo, pero tendrá que manejar esa porción de memoria usted mismo. Terminarías escribiendo tu propio malloc () preocupado por este fragmento.

Con respecto a:

  

Después de alguna prueba y error encontré el   arriba está la matriz estática más grande   permitido en mi máquina Intel de 32 bits   con GCC 4.3. ¿Es esto un estándar?   límite, un límite del compilador o una máquina   límite?

Un límite superior dependerá de cómo se divide el espacio de direcciones virtuales de 4 GB (32 bits) entre el espacio del usuario y el espacio del núcleo. Para Linux, creo que el esquema de particionamiento más común tiene un rango de direcciones de 3 GB para espacio de usuario y un rango de direcciones de 1 GB para espacio de núcleo. La partición es configurable en el tiempo de construcción del kernel, también se usan divisiones de 2GB / 2GB y 1GB / 3GB. Cuando se carga el ejecutable, se debe asignar espacio de dirección virtual para cada objeto, independientemente de si se asigna memoria real para realizar una copia de seguridad.

Es posible que pueda asignar esa matriz gigantesca en un contexto, pero no en otros. Por ejemplo, si su matriz es miembro de una estructura y desea pasar la estructura. Algunos entornos tienen un límite de 32K en el tamaño de la estructura.

Como se mencionó anteriormente, también puede cambiar el tamaño de su memoria para usar exactamente lo que necesita. Es importante en contextos críticos de rendimiento no paginar a la memoria virtual si se puede evitar.

No hay forma de liberar la asignación de la pila que no sea salir del alcance. Por lo tanto, cuando realmente utiliza la asignación global y VM tiene que asignarle la memoria física real, se asigna y permanecerá allí hasta que se agote el programa. Esto significa que cualquier proceso solo crecerá en su uso de memoria virtual (las funciones tienen asignaciones de pila locales y esas serán '' liberadas '').

No puede " mantener " la memoria de la pila una vez que sale del alcance de la función, siempre se libera. Entonces debe saber cuánta memoria usará en el momento de la compilación.

Que luego se reduce a cuántos int foo [1 < < 29] puede tener. Como el primero ocupa toda la memoria (en 32 bits) y será (vamos a mentir: 0x000000) el segundo se resolverá en 0xffffffff o más o menos. ¿Entonces el tercero resolvería a qué? Algo que los punteros de 32 bits no pueden expresar. (recuerde que las reservas de pila se resuelven parcialmente en tiempo de compilación, parcialmente en tiempo de ejecución, mediante compensaciones, hasta qué punto se empuja el desplazamiento de pila cuando asigna esta o aquella variable).

Entonces, la respuesta es más o menos que una vez que tienes int foo [1 < < 29] ya no puedes tener ninguna profundidad razonable de funciones con otras variables de pila locales.

Realmente deberías evitar hacer esto a menos que sepas lo que estás haciendo. Intenta solicitar solo la memoria que necesites. Incluso si no se está utilizando o interfiere con otros programas, puede estropear el proceso por sí mismo. Hay dos razones para esto. Primero, en ciertos sistemas, particularmente los de 32 bits, puede provocar que el espacio de direcciones se agote prematuramente en circunstancias excepcionales. Además, muchos núcleos tienen algún tipo de límite por proceso en memoria reservada / virtual / no en uso. Si su programa solicita memoria en puntos en tiempo de ejecución, el núcleo puede matar el proceso si solicita que se reserve una memoria que exceda este límite. He visto programas que se han bloqueado o salido debido a un malloc fallido porque están reservando GB de memoria mientras solo usan unos pocos MB.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top